mirror of
https://github.com/EGroupware/egroupware.git
synced 2025-06-19 17:38:06 +02:00
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(
|
'owner' => array(
|
||||||
'key' => 'egw_addressbook.contact_id',
|
'key' => 'egw_addressbook.contact_id',
|
||||||
'column' => 'egw_addressbook.contact_owner'
|
'column' => 'egw_addressbook.contact_owner'
|
||||||
)
|
),
|
||||||
|
'push_data' => ['owner','tid','cat_id']
|
||||||
);
|
);
|
||||||
return $links;
|
return $links;
|
||||||
}
|
}
|
||||||
|
@ -44,8 +44,13 @@ var AddressbookApp = /** @class */ (function (_super) {
|
|||||||
* @memberOf app.addressbook
|
* @memberOf app.addressbook
|
||||||
*/
|
*/
|
||||||
function AddressbookApp() {
|
function AddressbookApp() {
|
||||||
|
var _this =
|
||||||
// call parent
|
// 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
|
* Destructor
|
||||||
@ -1231,9 +1236,8 @@ var AddressbookApp = /** @class */ (function (_super) {
|
|||||||
* Remove the entry again, if user is not allowed
|
* Remove the entry again, if user is not allowed
|
||||||
*/
|
*/
|
||||||
AddressbookApp.prototype.shared_changed = function () {
|
AddressbookApp.prototype.shared_changed = function () {
|
||||||
var _a;
|
|
||||||
var shared = this.et2.getInputWidgetById('shared_values');
|
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) {
|
if (value) {
|
||||||
this.egw.json('addressbook.addressbook_ui.ajax_check_shared', [{
|
this.egw.json('addressbook.addressbook_ui.ajax_check_shared', [{
|
||||||
contact: this.et2.getInstanceManager().getValues(this.et2),
|
contact: this.et2.getInstanceManager().getValues(this.et2),
|
||||||
|
@ -27,6 +27,10 @@ import {etemplate2} from "../../api/js/etemplate/etemplate2";
|
|||||||
*/
|
*/
|
||||||
class AddressbookApp extends EgwApp
|
class AddressbookApp extends EgwApp
|
||||||
{
|
{
|
||||||
|
// These fields help with push
|
||||||
|
protected push_grant_fields = ["owner"];
|
||||||
|
protected push_filter_fields = ["tid","owner","cat_id"]
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*
|
*
|
||||||
|
@ -55,6 +55,7 @@ var __extends = (this && this.__extends) || (function () {
|
|||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
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_common");
|
||||||
require("./et2_core_interfaces");
|
require("./et2_core_interfaces");
|
||||||
var et2_core_inheritance_1 = require("./et2_core_inheritance");
|
var et2_core_inheritance_1 = require("./et2_core_inheritance");
|
||||||
@ -1921,11 +1922,10 @@ var et2_nextmatch = /** @class */ (function (_super) {
|
|||||||
* @param {object} target
|
* @param {object} target
|
||||||
*/
|
*/
|
||||||
et2_nextmatch.prototype.handle_drop = function (event, target) {
|
et2_nextmatch.prototype.handle_drop = function (event, target) {
|
||||||
var _a;
|
|
||||||
// Check to see if we can handle the link
|
// Check to see if we can handle the link
|
||||||
// First, find the UID
|
// First, find the UID
|
||||||
var row = this.controller.getRowByNode(target);
|
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
|
// Get the file information
|
||||||
var files = [];
|
var files = [];
|
||||||
if (event.originalEvent && event.originalEvent.dataTransfer &&
|
if (event.originalEvent && event.originalEvent.dataTransfer &&
|
||||||
@ -2014,7 +2014,8 @@ var et2_nextmatch = /** @class */ (function (_super) {
|
|||||||
idsArr[i] = idsArr[i].split("::").pop();
|
idsArr[i] = idsArr[i].split("::").pop();
|
||||||
}
|
}
|
||||||
var value = {
|
var value = {
|
||||||
"selected": idsArr
|
"selected": idsArr,
|
||||||
|
col_filter: {}
|
||||||
};
|
};
|
||||||
jQuery.extend(value, this.activeFilters, this.value);
|
jQuery.extend(value, this.activeFilters, this.value);
|
||||||
return value;
|
return value;
|
||||||
|
@ -2707,7 +2707,8 @@ export class et2_nextmatch extends et2_DOMWidget implements et2_IResizeable, et2
|
|||||||
idsArr[i] = idsArr[i].split("::").pop();
|
idsArr[i] = idsArr[i].split("::").pop();
|
||||||
}
|
}
|
||||||
const value = {
|
const value = {
|
||||||
"selected": idsArr
|
"selected": idsArr,
|
||||||
|
col_filter: {}
|
||||||
};
|
};
|
||||||
jQuery.extend(value, this.activeFilters, this.value);
|
jQuery.extend(value, this.activeFilters, this.value);
|
||||||
return 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
|
// don't care about other apps data, reimplement if your app does care eg. calendar
|
||||||
if (pushData.app !== this.appname)
|
if (pushData.app !== this.appname)
|
||||||
return;
|
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))) {
|
if (pushData.type === 'delete' && egw.dataHasUID(this.uid(pushData))) {
|
||||||
egw.refresh('', pushData.app, pushData.id, 'delete');
|
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
|
* Get (possible) app-specific uid
|
||||||
|
@ -131,6 +131,22 @@ export abstract class EgwApp
|
|||||||
*/
|
*/
|
||||||
static _instances: 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
|
* Initialization and setup goes here, but the etemplate2 object
|
||||||
* is not yet ready.
|
* 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
|
// don't care about other apps data, reimplement if your app does care eg. calendar
|
||||||
if (pushData.app !== this.appname) return;
|
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)))
|
if (pushData.type === 'delete' && egw.dataHasUID(this.uid(pushData)))
|
||||||
{
|
{
|
||||||
egw.refresh('', pushData.app, pushData.id, 'delete');
|
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…
x
Reference in New Issue
Block a user