forked from extern/egroupware
Enable push for addressbook
Refactor EgwApp.push() to cover more common stuff for simpler app code
This commit is contained in:
parent
2a2f0bf390
commit
3c72462b5e
@ -408,7 +408,8 @@ class addressbook_hooks
|
||||
'owner' => array(
|
||||
'key' => 'egw_addressbook.contact_id',
|
||||
'column' => 'egw_addressbook.contact_owner'
|
||||
)
|
||||
),
|
||||
'push_data' => ['owner','tid','cat_id']
|
||||
);
|
||||
return $links;
|
||||
}
|
||||
|
@ -44,8 +44,13 @@ var AddressbookApp = /** @class */ (function (_super) {
|
||||
* @memberOf app.addressbook
|
||||
*/
|
||||
function AddressbookApp() {
|
||||
var _this =
|
||||
// call parent
|
||||
return _super.call(this, 'addressbook') || this;
|
||||
_super.call(this, 'addressbook') || this;
|
||||
// These fields help with push
|
||||
_this.push_grant_fields = ["owner"];
|
||||
_this.push_filter_fields = ["tid", "owner", "cat_id"];
|
||||
return _this;
|
||||
}
|
||||
/**
|
||||
* Destructor
|
||||
@ -1231,9 +1236,8 @@ var AddressbookApp = /** @class */ (function (_super) {
|
||||
* Remove the entry again, if user is not allowed
|
||||
*/
|
||||
AddressbookApp.prototype.shared_changed = function () {
|
||||
var _a;
|
||||
var shared = this.et2.getInputWidgetById('shared_values');
|
||||
var value = (_a = shared) === null || _a === void 0 ? void 0 : _a.get_value();
|
||||
var value = shared === null || shared === void 0 ? void 0 : shared.get_value();
|
||||
if (value) {
|
||||
this.egw.json('addressbook.addressbook_ui.ajax_check_shared', [{
|
||||
contact: this.et2.getInstanceManager().getValues(this.et2),
|
||||
|
@ -27,6 +27,10 @@ import {etemplate2} from "../../api/js/etemplate/etemplate2";
|
||||
*/
|
||||
class AddressbookApp extends EgwApp
|
||||
{
|
||||
// These fields help with push
|
||||
protected push_grant_fields = ["owner"];
|
||||
protected push_filter_fields = ["tid","owner","cat_id"]
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
|
@ -55,6 +55,7 @@ var __extends = (this && this.__extends) || (function () {
|
||||
};
|
||||
})();
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.et2_nextmatch_accountfilterheader = exports.et2_nextmatch_filterheader = exports.et2_nextmatch_sortheader = exports.et2_nextmatch_customfields = exports.et2_nextmatch_header = exports.et2_nextmatch = void 0;
|
||||
require("./et2_core_common");
|
||||
require("./et2_core_interfaces");
|
||||
var et2_core_inheritance_1 = require("./et2_core_inheritance");
|
||||
@ -1921,11 +1922,10 @@ var et2_nextmatch = /** @class */ (function (_super) {
|
||||
* @param {object} target
|
||||
*/
|
||||
et2_nextmatch.prototype.handle_drop = function (event, target) {
|
||||
var _a;
|
||||
// Check to see if we can handle the link
|
||||
// First, find the UID
|
||||
var row = this.controller.getRowByNode(target);
|
||||
var uid = ((_a = row) === null || _a === void 0 ? void 0 : _a.uid) || null;
|
||||
var uid = (row === null || row === void 0 ? void 0 : row.uid) || null;
|
||||
// Get the file information
|
||||
var files = [];
|
||||
if (event.originalEvent && event.originalEvent.dataTransfer &&
|
||||
@ -2014,7 +2014,8 @@ var et2_nextmatch = /** @class */ (function (_super) {
|
||||
idsArr[i] = idsArr[i].split("::").pop();
|
||||
}
|
||||
var value = {
|
||||
"selected": idsArr
|
||||
"selected": idsArr,
|
||||
col_filter: {}
|
||||
};
|
||||
jQuery.extend(value, this.activeFilters, this.value);
|
||||
return value;
|
||||
|
@ -2707,7 +2707,8 @@ export class et2_nextmatch extends et2_DOMWidget implements et2_IResizeable, et2
|
||||
idsArr[i] = idsArr[i].split("::").pop();
|
||||
}
|
||||
const value = {
|
||||
"selected": idsArr
|
||||
"selected": idsArr,
|
||||
col_filter: {}
|
||||
};
|
||||
jQuery.extend(value, this.activeFilters, this.value);
|
||||
return value;
|
||||
|
@ -163,10 +163,107 @@ var EgwApp = /** @class */ (function () {
|
||||
// don't care about other apps data, reimplement if your app does care eg. calendar
|
||||
if (pushData.app !== this.appname)
|
||||
return;
|
||||
// only handle delete by default, for simple case of uid === "$app::$id"
|
||||
// handle delete, for simple case of uid === "$app::$id"
|
||||
if (pushData.type === 'delete' && egw.dataHasUID(this.uid(pushData))) {
|
||||
egw.refresh('', pushData.app, pushData.id, 'delete');
|
||||
return;
|
||||
}
|
||||
// If we know about it and it's an update, just update.
|
||||
// This must be before all ACL checks, as responsible might have changed and entry need to be removed
|
||||
// (server responds then with null / no entry causing the entry to disappear)
|
||||
if (pushData.type !== "add" && this.egw.dataHasUID(this.uid(pushData))) {
|
||||
return this.et2.getInstanceManager().refresh("", pushData.app, pushData.id, pushData.type);
|
||||
}
|
||||
// Check grants to see if we know we aren't supposed to show it
|
||||
if (typeof this.push_grant_fields !== "undefined" && this.push_grant_fields.length > 0
|
||||
&& !this._push_grant_check(pushData, this.push_grant_fields)) {
|
||||
return;
|
||||
}
|
||||
// Nextmatch does the hard part of updating. Try to find one.
|
||||
var nm = this.et2.getDOMWidgetById('nm');
|
||||
if (!nm) {
|
||||
return;
|
||||
}
|
||||
// Filter what's allowed down to those we can see / care about based on nm filters
|
||||
if (typeof this.push_filter_fields !== "undefined" && this.push_filter_fields.length > 0 &&
|
||||
!this._push_field_filter(pushData, nm, this.push_filter_fields)) {
|
||||
return;
|
||||
}
|
||||
// Pass actual refresh on to just nextmatch
|
||||
nm.refresh(pushData.id, pushData.type);
|
||||
};
|
||||
/**
|
||||
* Check grants to see if we can quickly tell if this entry is not for us
|
||||
*
|
||||
* Override this method if the app has non-standard access control.
|
||||
*
|
||||
* @param pushData
|
||||
* @param grant_fields List of fields in pushData.acl with account IDs that might grant access eg: info_responsible
|
||||
*/
|
||||
EgwApp.prototype._push_grant_check = function (pushData, grant_fields) {
|
||||
var grants = egw.grants(this.appname);
|
||||
// check user has a grant from owner or something
|
||||
for (var i = 0; i < grant_fields.length; i++) {
|
||||
if (grants && typeof grants[pushData.acl[grant_fields[i]]] !== 'undefined') {
|
||||
// ACL access
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
/**
|
||||
* Check pushData.acl values against a list of fields to see if we care about this entry based on current nextmatch
|
||||
* filter values. This is not a definitive yes or no (the server will tell us when we ask), we just want to cheaply
|
||||
* avoid a server call if we know it won't be in the list.
|
||||
*
|
||||
* @param pushData
|
||||
* @param filter_fields List of filter field names eg: [owner, cat_id]
|
||||
* @return boolean True if the nextmatch filters might include the entry, false if not
|
||||
*/
|
||||
EgwApp.prototype._push_field_filter = function (pushData, nm, filter_fields) {
|
||||
var filters = {};
|
||||
for (var i = 0; i < filter_fields.length; i++) {
|
||||
filters[filter_fields[i]] = {
|
||||
col: filter_fields[i],
|
||||
filter_values: []
|
||||
};
|
||||
}
|
||||
// Get current filter values
|
||||
if (this.et2) {
|
||||
var value = nm.getValue();
|
||||
if (!value || !value.col_filter)
|
||||
return false;
|
||||
for (var _i = 0, _a = Object.values(filters); _i < _a.length; _i++) {
|
||||
var field_filter = _a[_i];
|
||||
if (value.col_filter[field_filter.col]) {
|
||||
field_filter.filter_values.push(value.col_filter[field_filter.col]);
|
||||
}
|
||||
}
|
||||
}
|
||||
var _loop_1 = function (field_filter) {
|
||||
// no filter set
|
||||
if (field_filter.filter_values.length == 0)
|
||||
return "continue";
|
||||
// acl value is a scalar (not array) --> check contained in filter
|
||||
if (pushData.acl && typeof pushData.acl[field_filter.col] !== 'object') {
|
||||
if (field_filter.filter_values.indexOf(pushData.acl[field_filter.col]) < 0) {
|
||||
return { value: false };
|
||||
}
|
||||
return "continue";
|
||||
}
|
||||
// acl value is an array (eg. tr_assigned) --> check intersection with filter
|
||||
if (!field_filter.filter_values.filter(function (account) { return pushData.acl[field_filter.col].indexOf(account) >= 0; }).length) {
|
||||
return { value: false };
|
||||
}
|
||||
};
|
||||
// check filters against pushData.acl data
|
||||
for (var _b = 0, _c = Object.values(filters); _b < _c.length; _b++) {
|
||||
var field_filter = _c[_b];
|
||||
var state_1 = _loop_1(field_filter);
|
||||
if (typeof state_1 === "object")
|
||||
return state_1.value;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
/**
|
||||
* Get (possible) app-specific uid
|
||||
|
@ -131,6 +131,22 @@ export abstract class EgwApp
|
||||
*/
|
||||
static _instances: EgwApp[] = [];
|
||||
|
||||
/**
|
||||
* If pushData.acl has fields that can help filter based on ACL grants, list them
|
||||
* here and we can check them and ignore push messages if there is no ACL for that entry
|
||||
*
|
||||
* @protected
|
||||
*/
|
||||
protected push_grant_fields: string[];
|
||||
|
||||
/**
|
||||
* If pushData.acl has fields that can help filter based on current nextmatch filters,
|
||||
* list them here and we can check and ignore push messages if the nextmatch filters do not exclude them
|
||||
*
|
||||
* @protected
|
||||
*/
|
||||
protected push_filter_fields: string[];
|
||||
|
||||
/**
|
||||
* Initialization and setup goes here, but the etemplate2 object
|
||||
* is not yet ready.
|
||||
@ -259,11 +275,129 @@ export abstract class EgwApp
|
||||
// don't care about other apps data, reimplement if your app does care eg. calendar
|
||||
if (pushData.app !== this.appname) return;
|
||||
|
||||
// only handle delete by default, for simple case of uid === "$app::$id"
|
||||
// handle delete, for simple case of uid === "$app::$id"
|
||||
if (pushData.type === 'delete' && egw.dataHasUID(this.uid(pushData)))
|
||||
{
|
||||
egw.refresh('', pushData.app, pushData.id, 'delete');
|
||||
return;
|
||||
}
|
||||
|
||||
// If we know about it and it's an update, just update.
|
||||
// This must be before all ACL checks, as responsible might have changed and entry need to be removed
|
||||
// (server responds then with null / no entry causing the entry to disappear)
|
||||
if (pushData.type !== "add" && this.egw.dataHasUID(this.uid(pushData)))
|
||||
{
|
||||
return this.et2.getInstanceManager().refresh("", pushData.app, pushData.id, pushData.type);
|
||||
}
|
||||
|
||||
// Check grants to see if we know we aren't supposed to show it
|
||||
if(typeof this.push_grant_fields !== "undefined" && this.push_grant_fields.length > 0
|
||||
&& !this._push_grant_check(pushData, this.push_grant_fields)
|
||||
)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Nextmatch does the hard part of updating. Try to find one.
|
||||
let nm = <et2_nextmatch>this.et2.getDOMWidgetById('nm');
|
||||
if(!nm)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Filter what's allowed down to those we can see / care about based on nm filters
|
||||
if(typeof this.push_filter_fields !== "undefined" && this.push_filter_fields.length > 0 &&
|
||||
!this._push_field_filter(pushData, nm, this.push_filter_fields)
|
||||
)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Pass actual refresh on to just nextmatch
|
||||
nm.refresh(pushData.id, pushData.type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check grants to see if we can quickly tell if this entry is not for us
|
||||
*
|
||||
* Override this method if the app has non-standard access control.
|
||||
*
|
||||
* @param pushData
|
||||
* @param grant_fields List of fields in pushData.acl with account IDs that might grant access eg: info_responsible
|
||||
*/
|
||||
_push_grant_check(pushData : PushData, grant_fields : string[]) : boolean
|
||||
{
|
||||
let grants = egw.grants(this.appname);
|
||||
|
||||
// check user has a grant from owner or something
|
||||
for(let i = 0; i < grant_fields.length; i++)
|
||||
{
|
||||
if(grants && typeof grants[pushData.acl[grant_fields[i]]] !== 'undefined')
|
||||
{
|
||||
// ACL access
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check pushData.acl values against a list of fields to see if we care about this entry based on current nextmatch
|
||||
* filter values. This is not a definitive yes or no (the server will tell us when we ask), we just want to cheaply
|
||||
* avoid a server call if we know it won't be in the list.
|
||||
*
|
||||
* @param pushData
|
||||
* @param filter_fields List of filter field names eg: [owner, cat_id]
|
||||
* @return boolean True if the nextmatch filters might include the entry, false if not
|
||||
*/
|
||||
_push_field_filter(pushData : PushData, nm : et2_nextmatch, filter_fields: string[]) : boolean
|
||||
{
|
||||
let filters = {};
|
||||
for(let i = 0; i < filter_fields.length; i++)
|
||||
{
|
||||
filters[filter_fields[i]] = {
|
||||
col: filter_fields[i],
|
||||
filter_values: []
|
||||
};
|
||||
}
|
||||
|
||||
// Get current filter values
|
||||
if(this.et2)
|
||||
{
|
||||
let value = nm.getValue();
|
||||
if(!value || !value.col_filter) return false;
|
||||
|
||||
for(let field_filter of Object.values(filters))
|
||||
{
|
||||
if(value.col_filter[field_filter.col])
|
||||
{
|
||||
field_filter.filter_values.push(value.col_filter[field_filter.col]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check filters against pushData.acl data
|
||||
for(let field_filter of Object.values(filters))
|
||||
{
|
||||
// no filter set
|
||||
if (field_filter.filter_values.length == 0) continue;
|
||||
|
||||
// acl value is a scalar (not array) --> check contained in filter
|
||||
if (pushData.acl && typeof pushData.acl[field_filter.col] !== 'object')
|
||||
{
|
||||
if (field_filter.filter_values.indexOf(pushData.acl[field_filter.col]) < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// acl value is an array (eg. tr_assigned) --> check intersection with filter
|
||||
if(!field_filter.filter_values.filter(account => pushData.acl[field_filter.col].indexOf(account) >= 0).length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user