initial commit
This commit is contained in:
commit
ecaa6e3a35
198
build.xml
Executable file
198
build.xml
Executable file
@ -0,0 +1,198 @@
|
||||
<project default="all">
|
||||
<property environment="env"/>
|
||||
<property name="root-folder" value="${basedir}/../../"/>
|
||||
<property name="tools-folder" value="${root-folder}/tools/"/>
|
||||
<property name="target-folder" value="${root-folder}/deploy/plugins"/>
|
||||
<property name="server-folder" value="${root-folder}/server"/>
|
||||
|
||||
<import file="${tools-folder}/antutil.xml"/>
|
||||
|
||||
<typedef file="${tools-folder}/antlib.xml">
|
||||
<classpath>
|
||||
<pathelement location="${tools-folder}/tools.jar"/>
|
||||
</classpath>
|
||||
</typedef>
|
||||
|
||||
<taskdef resource="net/sf/antcontrib/antcontrib.properties">
|
||||
<classpath>
|
||||
<pathelement location="${tools-folder}/lib/ant-contrib-1.0b3.jar"/>
|
||||
</classpath>
|
||||
</taskdef>
|
||||
|
||||
<!-- Determine plugin name -->
|
||||
<basename file="${basedir}" property="plugin"/>
|
||||
|
||||
<!-- The Plugin distribution files -->
|
||||
<property name="plugin-folder" value="${plugin}"/>
|
||||
<property name="plugin-debugfile" value="${plugin}-debug.js"/>
|
||||
<property name="plugin-file" value="${plugin}.js"/>
|
||||
|
||||
<!-- The Plugin CSS files -->
|
||||
<property name="plugin-css-folder" value="resources/css"/>
|
||||
<property name="plugin-css-file" value="${plugin}.css"/>
|
||||
|
||||
<!-- Meta target -->
|
||||
<target name="all" depends="concat, compress"/>
|
||||
|
||||
<!-- Clean -->
|
||||
<target name="clean">
|
||||
<delete includeemptydirs="true" failonerror="false">
|
||||
<!-- Delete the Plugin files -->
|
||||
<fileset dir="${target-folder}/${plugin-folder}/js">
|
||||
<include name="${plugin-file}"/>
|
||||
<include name="${plugin-debugfile}"/>
|
||||
</fileset>
|
||||
</delete>
|
||||
</target>
|
||||
|
||||
<!-- Concatenates JavaScript files with automatic dependency generation -->
|
||||
<target name="concat">
|
||||
<!-- Concatenate plugin JS file -->
|
||||
<if>
|
||||
<available file="js" type="dir" />
|
||||
<then>
|
||||
<mkdir dir="${target-folder}/${plugin-folder}/js"/>
|
||||
<echo message="Concatenating: ${plugin-debugfile}"/>
|
||||
<zConcat outputFolder="${target-folder}/${plugin-folder}/js" outputFile="${plugin-debugfile}" prioritize="\w+">
|
||||
<concatfiles>
|
||||
<fileset dir="js" includes="**/*.js" />
|
||||
</concatfiles>
|
||||
</zConcat>
|
||||
</then>
|
||||
</if>
|
||||
|
||||
<!-- Concatenate plugin CSS files -->
|
||||
<if>
|
||||
<available file="${plugin-css-folder}" type="dir" />
|
||||
<then>
|
||||
<mkdir dir="${target-folder}/${plugin-folder}/${plugin-css-folder}"/>
|
||||
<echo message="Concatenating: ${plugin-css-file}"/>
|
||||
<zConcat outputFolder="${target-folder}/${plugin-folder}/${plugin-css-folder}" outputFile="${plugin-css-file}">
|
||||
<concatfiles>
|
||||
<fileset dir="${plugin-css-folder}" includes="**/*.css" />
|
||||
</concatfiles>
|
||||
</zConcat>
|
||||
</then>
|
||||
</if>
|
||||
</target>
|
||||
|
||||
<!-- Preformat the Concatenated Javascript files to improve compilation -->
|
||||
<target name="preformat" depends="concat">
|
||||
<if>
|
||||
<available file="${target-folder}/${plugin-folder}/js/${plugin-debugfile}" type="file" />
|
||||
<then>
|
||||
<echo message="Preformatting: ${plugin-debugfile}"/>
|
||||
<replaceregexp byline="true">
|
||||
<regexp pattern="(^[ ,\t]*\*[ ,\t]@.*)\{(.*)\[\]\}"/>
|
||||
<substitution expression="\1{\2\|Array}"/>
|
||||
<fileset dir="${target-folder}/${plugin-folder}/js" includes="${plugin-debugfile}"/>
|
||||
</replaceregexp>
|
||||
</then>
|
||||
</if>
|
||||
</target>
|
||||
|
||||
<!-- Compress JavaScript -->
|
||||
<target name="compress" depends="preformat">
|
||||
<if>
|
||||
<available file="${target-folder}/${plugin-folder}/js/${plugin-debugfile}" type="file" />
|
||||
<then>
|
||||
<echo message="Compiling: ${plugin-debugfile}" />
|
||||
<zCompile inputFolder="${target-folder}/${plugin-folder}/js" inputFile="${plugin-debugfile}" outputFolder="${target-folder}/${plugin-folder}/js" outputFile="${plugin-file}">
|
||||
<externs>
|
||||
var Ext = {};
|
||||
var Zarafa = {};
|
||||
var container = {};
|
||||
var _ = function(key, domain) {};
|
||||
var dgettext = function(domain, msgid) {};
|
||||
var dngettext = function(domain, msgid, msgid_plural, count) {};
|
||||
var dnpgettext = function(domain, msgctxt, msgid, msgid_plural, count) {};
|
||||
var dpgettext = function(domain, msgctxt, msgid) {};
|
||||
var ngettext = function(msgid, msgid_plural, count) {};
|
||||
var npgettext = function(msgctxt, msgid, msgid_plural, count) {};
|
||||
var pgettext = function(msgctxt, msgid) {};
|
||||
</externs>
|
||||
</zCompile>
|
||||
</then>
|
||||
</if>
|
||||
</target>
|
||||
|
||||
<!-- syntax check all PHP files -->
|
||||
<target name="validate">
|
||||
<if>
|
||||
<available file="php" filepath="${env.PATH}" />
|
||||
<then>
|
||||
<if>
|
||||
<available file="config.php" type="file" />
|
||||
<then>
|
||||
<antcall target="syntax-check">
|
||||
<param name="file" value="config.php"/>
|
||||
</antcall>
|
||||
</then>
|
||||
</if>
|
||||
<if>
|
||||
<available file="php" type="dir" />
|
||||
<then>
|
||||
<foreach target="syntax-check" param="file">
|
||||
<path>
|
||||
<fileset dir=".">
|
||||
<include name="**/*.php"/>
|
||||
</fileset>
|
||||
</path>
|
||||
</foreach>
|
||||
</then>
|
||||
</if>
|
||||
</then>
|
||||
<else>
|
||||
<echo message="WARNING: PHP not available, not performing syntax-check on php files"/>
|
||||
</else>
|
||||
</if>
|
||||
</target>
|
||||
|
||||
<target name="syntax-check">
|
||||
<echo message="validating ${file}"/>
|
||||
<exec executable="php" failonerror="true">
|
||||
<arg value="-l"/>
|
||||
<arg value="${file}"/>
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<!-- Install all files into the target folder -->
|
||||
<target name="deploy" depends="compress, validate">
|
||||
<mkdir dir="${target-folder}/${plugin-folder}"/>
|
||||
|
||||
<!-- Copy (and validate) manifest.xml -->
|
||||
<if>
|
||||
<available file="xmllint" filepath="${env.PATH}" />
|
||||
<then>
|
||||
<exec executable="xmllint" output="${target-folder}/${plugin-folder}/manifest.xml" failonerror="true" logError="true">
|
||||
<arg value="--valid"/>
|
||||
<arg value="--path"/>
|
||||
<arg value="${server-folder}"/>
|
||||
<arg value="manifest.xml"/>
|
||||
</exec>
|
||||
</then>
|
||||
<else>
|
||||
<echo message="WARNING: xmllint not available, not performing syntax-check on manifest.xml"/>
|
||||
<!-- xmllint is not available, so we must copy the file manually -->
|
||||
<copy todir="${target-folder}/${plugin-folder}">
|
||||
<fileset dir=".">
|
||||
<include name="manifest.xml"/>
|
||||
</fileset>
|
||||
</copy>
|
||||
</else>
|
||||
</if>
|
||||
|
||||
<!-- copy files -->
|
||||
<copy todir="${target-folder}/${plugin-folder}">
|
||||
<fileset dir=".">
|
||||
<include name="resources/**/*.*"/>
|
||||
<include name="php/**/*.php"/>
|
||||
<include name="config.php"/>
|
||||
<!-- exclude the ant script -->
|
||||
<exclude name="build.xml"/>
|
||||
<!-- CSS is generated during build -->
|
||||
<exclude name="resources/css/*.*"/>
|
||||
</fileset>
|
||||
</copy>
|
||||
</target>
|
||||
</project>
|
5
config.php
Executable file
5
config.php
Executable file
@ -0,0 +1,5 @@
|
||||
<?php
|
||||
define('PLUGIN_MDM_USER_DEFAULT_ENABLE_MDM', false);
|
||||
define('PLUGIN_MDM_SERVER', 'localhost');
|
||||
define('PLUGIN_MDM_SERVER_SSL', false);
|
||||
?>
|
0
js/ABOUT.js
Executable file
0
js/ABOUT.js
Executable file
50
js/MDM.js
Executable file
50
js/MDM.js
Executable file
@ -0,0 +1,50 @@
|
||||
Ext.namespace('Zarafa.plugins.mdm');
|
||||
|
||||
/**
|
||||
* @class Zarafa.plugins.mdm.MDM
|
||||
* @extends Zarafa.core.Plugin
|
||||
*
|
||||
* Plugin which lists all devices connected to a Kopano account with Z-Push.
|
||||
* The user can wipe, resync, remove a device using buttons in the WebApp.
|
||||
*/
|
||||
Zarafa.plugins.mdm.MDM = Ext.extend(Zarafa.core.Plugin, {
|
||||
/**
|
||||
* Constructor
|
||||
* @param {Object} config
|
||||
* @protected
|
||||
*/
|
||||
constructor : function(config) {
|
||||
config = config || {};
|
||||
Zarafa.plugins.mdm.MDM.superclass.constructor.call(this, config);
|
||||
},
|
||||
|
||||
/**
|
||||
* Called after constructor.
|
||||
* Registers insertion points.
|
||||
* @protected
|
||||
*/
|
||||
initPlugin : function()
|
||||
{
|
||||
this.registerInsertionPoint('context.settings.categories', this.createSettingCategory, this);
|
||||
Zarafa.plugins.mdm.MDM.superclass.initPlugin.apply(this, arguments);
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates a category in settings for Z-Push
|
||||
* @return {mdmsettingscategory}
|
||||
*/
|
||||
createSettingCategory: function() {
|
||||
return [{
|
||||
xtype : 'Zarafa.plugins.mdm.mdmsettingscategory'
|
||||
}];
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
Zarafa.onReady(function() {
|
||||
container.registerPlugin(new Zarafa.core.PluginMetaData({
|
||||
name : 'mdm',
|
||||
displayName : _('Mobile device management'),
|
||||
pluginConstructor : Zarafa.plugins.mdm.MDM
|
||||
}));
|
||||
});
|
32
js/data/JsonDeviceReader.js
Normal file
32
js/data/JsonDeviceReader.js
Normal file
@ -0,0 +1,32 @@
|
||||
Ext.namespace('Zarafa.plugins.mdm.data');
|
||||
|
||||
/**
|
||||
* @class Zarafa.plugins.mdm.data.JsonCertificateReader
|
||||
* @extends Zarafa.core.data.JsonReader
|
||||
*/
|
||||
Zarafa.plugins.mdm.data.JsonCertificateReader = Ext.extend(Zarafa.core.data.JsonReader, {
|
||||
/**
|
||||
* @cfg {Zarafa.core.data.RecordCustomObjectType} customObjectType The custom object type
|
||||
* which represents the {@link Ext.data.Record records} which should be created using
|
||||
* {@link Zarafa.core.data.RecordFactory#createRecordObjectByCustomType}.
|
||||
*/
|
||||
customObjectType : Zarafa.core.data.RecordCustomObjectType.ZARAFA_MDM,
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @param {Object} meta Metadata configuration options.
|
||||
* @param {Object} recordType (optional) Optional Record type matches the type
|
||||
* which must be read from response. If no type is given, it will use the
|
||||
* record type for the {@link Zarafa.core.data.RecordCustomObjectType#ZARAFA_MDM}.
|
||||
*/
|
||||
constructor : function(meta, recordType)
|
||||
{
|
||||
meta = Ext.applyIf(meta || {}, {
|
||||
dynamicRecord : false
|
||||
});
|
||||
|
||||
recordType = Zarafa.core.data.RecordFactory.getRecordClassByCustomType(Zarafa.core.data.RecordCustomObjectType.ZARAFA_MDM);
|
||||
|
||||
Zarafa.plugins.mdm.data.JsonCertificateReader.superclass.constructor.call(this, meta, recordType);
|
||||
}
|
||||
});
|
33
js/data/MDMDeviceRecord.js
Normal file
33
js/data/MDMDeviceRecord.js
Normal file
@ -0,0 +1,33 @@
|
||||
Ext.namespace('Zarafa.plugins.mdm');
|
||||
|
||||
Zarafa.plugins.mdm.data.MDMDeviceRecordFields = [
|
||||
{name: 'entryid', type: 'string'},
|
||||
{name: 'changed', type: 'boolean'},
|
||||
{name: 'deviceos', type: 'string'},
|
||||
{name: 'devicefriendlyname', type: 'string'},
|
||||
{name: 'deviceinfo', type: 'string'},
|
||||
{name: 'devicetype', type: 'string'},
|
||||
{name: 'devicemodel', type: 'string'},
|
||||
{name: 'domain', type: 'string'},
|
||||
{name: 'hierarchyuuid', type: 'string'},
|
||||
// ignoredmessages
|
||||
{name: 'firstsynctime', type: 'date', dateFormat: 'timestamp'},
|
||||
{name: 'lastupdatetime', type: 'date', dateFormat: 'timestamp'},
|
||||
{name: 'wipestatus', type: 'string'},
|
||||
{name: 'useragent', type: 'string'}
|
||||
];
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
Zarafa.plugins.mdm.data.MDMDeviceRecord = Ext.extend(Zarafa.core.data.IPMRecord, {});
|
||||
Zarafa.core.data.RecordCustomObjectType.addProperty('ZARAFA_MDM');
|
||||
Zarafa.core.data.RecordFactory.addFieldToCustomType(Zarafa.core.data.RecordCustomObjectType.ZARAFA_MDM, Zarafa.plugins.mdm.data.MDMDeviceRecordFields);
|
||||
|
||||
Zarafa.core.data.RecordFactory.addListenerToCustomType(Zarafa.core.data.RecordCustomObjectType.ZARAFA_MDM, 'createphantom', function(record)
|
||||
{
|
||||
// Phantom records must always be marked as opened (they contain the full set of data)
|
||||
record.afterOpen();
|
||||
});
|
||||
|
||||
Zarafa.core.data.RecordFactory.setBaseClassToCustomType(Zarafa.core.data.RecordCustomObjectType.ZARAFA_MDM, Zarafa.plugins.mdm.data.MDMDeviceRecord);
|
33
js/data/MDMDeviceStore.js
Normal file
33
js/data/MDMDeviceStore.js
Normal file
@ -0,0 +1,33 @@
|
||||
Ext.namespace('Zarafa.plugins.mdm.data');
|
||||
|
||||
/**
|
||||
* @class Zarafa.plugins.mdm.data.MDMDeviceStore
|
||||
* @extends Zarafa.core.data.ListModuleStore
|
||||
* @xtype mdm.devicestore
|
||||
* Store specific for MDM Plugin which creates {@link Zarafa.plugins.mdm.MDMDeviceRecord record}.
|
||||
*/
|
||||
Zarafa.plugins.mdm.data.MDMDeviceStore = Ext.extend(Zarafa.core.data.ListModuleStore, {
|
||||
/**
|
||||
* @constructor
|
||||
* @param config Configuration object
|
||||
*/
|
||||
constructor : function(config)
|
||||
{
|
||||
config = config || {};
|
||||
|
||||
Ext.applyIf(config, {
|
||||
autoLoad : true,
|
||||
remoteSort: false,
|
||||
reader : new Zarafa.plugins.mdm.data.JsonCertificateReader(),
|
||||
writer : new Zarafa.core.data.JsonWriter(),
|
||||
proxy : new Zarafa.core.data.IPMProxy({
|
||||
listModuleName: 'pluginmdmmodule',
|
||||
itemModuleName: 'pluginmdmmodule'
|
||||
})
|
||||
});
|
||||
|
||||
Zarafa.plugins.mdm.data.MDMDeviceStore.superclass.constructor.call(this, config);
|
||||
}
|
||||
});
|
||||
|
||||
Ext.reg('mdm.devicestore', Zarafa.plugins.mdm.data.MDMDeviceStore);
|
0
js/data/MDMRecord.js
Normal file
0
js/data/MDMRecord.js
Normal file
74
js/data/MDMResponseHandler.js
Normal file
74
js/data/MDMResponseHandler.js
Normal file
@ -0,0 +1,74 @@
|
||||
Ext.namespace('Zarafa.plugins.mdm.data');
|
||||
|
||||
/**
|
||||
* @class Zarafa.plugins.mdm.data.MDMResponseHandler
|
||||
* @extends Zarafa.core.data.AbstractResponseHandler
|
||||
*
|
||||
* MDM specific response handler.
|
||||
*/
|
||||
Zarafa.plugins.mdm.data.MDMResponseHandler = Ext.extend(Zarafa.core.data.AbstractResponseHandler, {
|
||||
|
||||
/**
|
||||
* @cfg {Function} successCallback The function which
|
||||
* will be called after success request.
|
||||
*/
|
||||
successCallback : Ext.emptyFn,
|
||||
|
||||
/**
|
||||
* @cfg {Function} failureCallback The function which
|
||||
* will be called after a failed request.
|
||||
* This callback is optional and currently unused.
|
||||
*/
|
||||
failureCallback : Ext.emptyFn,
|
||||
|
||||
/**
|
||||
* Device information from Z-Push's soap call,
|
||||
* @param {Object} response Object contained the response data.
|
||||
*/
|
||||
doInfo : function(response) {
|
||||
this.successCallback(response);
|
||||
/*
|
||||
if(response.status != true && this.failureCallback != null) {
|
||||
this.failureCallback(response);
|
||||
} else {
|
||||
this.successCallback(response);
|
||||
}*/
|
||||
},
|
||||
|
||||
/**
|
||||
* Call the successCallback callback function if device was successfully removed from
|
||||
* z-push server.
|
||||
* @param {Object} response Object contained the response data.
|
||||
*/
|
||||
doRemove : function(response)
|
||||
{
|
||||
if(response.remove){
|
||||
this.successCallback();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* If wipe request response was successful, show informative message.
|
||||
* @param {Object} response Object contained the response data.
|
||||
*/
|
||||
doWipe : function(response) {
|
||||
if (response.wipe === true) {
|
||||
container.getNotifier().notify('info.mdm', _('Mobile Device Manager'), _('Wiping device'));
|
||||
} else {
|
||||
container.getNotifier().notify('info.mdm', _('Mobile Device Manager'), _('Password incorrect'));
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* If resync request response was successful, show informative message.
|
||||
* @param {Object} response Object contained the response data.
|
||||
*/
|
||||
doResync : function(response) {
|
||||
if (response.resync === true) {
|
||||
container.getNotifier().notify('info.mdm', _('Mobile Device Manager'), _('Full resync in progress'));
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
Ext.reg('mdm.responsehandler', Zarafa.plugins.mdm.data.MDMResponseHandler);
|
67
js/data/ProvisioningStatus.js
Normal file
67
js/data/ProvisioningStatus.js
Normal file
@ -0,0 +1,67 @@
|
||||
Ext.namespace('Zarafa.plugins.mdm.data');
|
||||
|
||||
/**
|
||||
* @class Zarafa.plugins.mdm.data.ProvisioningStatus
|
||||
* @extends Zarafa.core.Enum
|
||||
*
|
||||
* @singleton
|
||||
*/
|
||||
Zarafa.plugins.mdm.data.ProvisioningStatus = Zarafa.core.Enum.create({
|
||||
/**
|
||||
* Denotes that the wipe is not applicable.
|
||||
* @property
|
||||
* @type Number
|
||||
*/
|
||||
'NOT_APPLICABLE' : 0,
|
||||
|
||||
/**
|
||||
* Denotes that the wipe is ok.
|
||||
* @property
|
||||
* @type Number
|
||||
*/
|
||||
'OK' : 1,
|
||||
|
||||
/**
|
||||
* Denotes that the wipe is pending.
|
||||
* @property
|
||||
* @type Number
|
||||
*/
|
||||
'WIPE_PENDING' : 2,
|
||||
|
||||
/**
|
||||
* Denotes that the Wipe is requested.
|
||||
* @property
|
||||
* @type Number
|
||||
*/
|
||||
'WIPE_REQUESTED' : 4,
|
||||
|
||||
/**
|
||||
* Denotes that the Wipe is executed.
|
||||
* @property
|
||||
* @type Number
|
||||
*/
|
||||
'WIPE_EXECUTED' : 8,
|
||||
|
||||
/**
|
||||
* Return the display name for the given provisioning Status
|
||||
* @param {Zarafa.plugins.mdm.js.data.ProvisioningStatus} provisioningStatus The given provisioning status
|
||||
* @return {String} The display name for the provisioning status
|
||||
*/
|
||||
getDisplayName : function(provisioningStatus)
|
||||
{
|
||||
switch (provisioningStatus) {
|
||||
case Zarafa.plugins.mdm.data.ProvisioningStatus.NOT_APPLICABLE:
|
||||
return _('Not Applicable');
|
||||
case Zarafa.plugins.mdm.data.ProvisioningStatus.OK:
|
||||
return _('Ok');
|
||||
case Zarafa.plugins.mdm.data.ProvisioningStatus.WIPE_PENDING:
|
||||
return _('Wipe Pending');
|
||||
case Zarafa.plugins.mdm.data.ProvisioningStatus.WIPE_REQUESTED:
|
||||
return _('Wipe Requested');
|
||||
case Zarafa.plugins.mdm.data.ProvisioningStatus.WIPE_EXECUTED:
|
||||
return _('Wipe Executed');
|
||||
}
|
||||
return '';
|
||||
}
|
||||
});
|
||||
|
35
js/settings/MDMSettingsCategory.js
Executable file
35
js/settings/MDMSettingsCategory.js
Executable file
@ -0,0 +1,35 @@
|
||||
Ext.namespace('Zarafa.plugins.mdm.settings');
|
||||
|
||||
/*
|
||||
* Settings category entry for MDM
|
||||
* @extends
|
||||
*/
|
||||
|
||||
/**
|
||||
* @class Zarafa.plugins.mdm.settings.MDMSettingsCategory
|
||||
* @extends Zarafa.settings.ui.SettingsCategory
|
||||
* @xtype Zarafa.plugins.mdmsettingscategory
|
||||
*
|
||||
* The mdm settings category entry.
|
||||
*/
|
||||
Zarafa.plugins.mdm.settings.MDMSettingsCategory = Ext.extend(Zarafa.settings.ui.SettingsCategory, {
|
||||
/**
|
||||
* @constructor
|
||||
* @param {Object} config Configuration object
|
||||
*/
|
||||
constructor : function(config) {
|
||||
config = config || {};
|
||||
|
||||
Ext.applyIf(config, {
|
||||
title : _('MDM'),
|
||||
iconCls : 'icon_mdm_settings',
|
||||
items : [{
|
||||
xtype : 'Zarafa.plugins.mdm.mdmsettingswidget'
|
||||
}]
|
||||
});
|
||||
|
||||
Zarafa.plugins.mdm.settings.MDMSettingsCategory.superclass.constructor.call(this, config);
|
||||
}
|
||||
});
|
||||
|
||||
Ext.reg('Zarafa.plugins.mdm.mdmsettingscategory', Zarafa.plugins.mdm.settings.MDMSettingsCategory);
|
198
js/settings/MDMSettingsWidget.js
Normal file
198
js/settings/MDMSettingsWidget.js
Normal file
@ -0,0 +1,198 @@
|
||||
Ext.namespace('Zarafa.plugins.mdm.settings');
|
||||
|
||||
/**
|
||||
* @class Zarafa.plugins.mdm.settings.MDMSettingsWidget
|
||||
* @extends Zarafa.settings.ui.SettingsWidget
|
||||
*/
|
||||
Zarafa.plugins.mdm.settings.MDMSettingsWidget = Ext.extend(Zarafa.settings.ui.SettingsWidget, {
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @param {Object} config Configuration object
|
||||
*/
|
||||
constructor : function(config)
|
||||
{
|
||||
config = config || {};
|
||||
|
||||
var store = new Zarafa.plugins.mdm.data.MDMDeviceStore();
|
||||
Ext.applyIf(config, {
|
||||
title : _('Mobile Devices'),
|
||||
items : [{
|
||||
xtype : 'container',
|
||||
layout : 'column',
|
||||
items : [{
|
||||
xtype : 'grid',
|
||||
name : _('Devices'),
|
||||
ref : '../deviceGrid',
|
||||
height : 400,
|
||||
store : store,
|
||||
viewConfig : {
|
||||
forceFit : true,
|
||||
deferEmptyText: false,
|
||||
emptyText: '<div class="emptytext">' + _('No devices connected to your account') + '</div>'
|
||||
},
|
||||
columns : [{
|
||||
dataIndex : 'devicetype',
|
||||
header : _('Device'),
|
||||
renderer : Ext.util.Format.htmlEncode
|
||||
},{
|
||||
dataIndex : 'useragent',
|
||||
header : _('User Agent'),
|
||||
renderer : Ext.util.Format.htmlEncode
|
||||
},{
|
||||
dataIndex : 'wipestatus',
|
||||
header : _('Provisioning Status'),
|
||||
renderer : Zarafa.plugins.mdm.ui.Renderers.provisioningStatus
|
||||
},{
|
||||
dataIndex : 'lastupdatetime',
|
||||
header : _('Last Update'),
|
||||
renderer : Ext.util.Format.htmlEncode
|
||||
},{
|
||||
dataIndex : 'entryid',
|
||||
header : _('Device ID'),
|
||||
renderer : Ext.util.Format.htmlEncode
|
||||
},{
|
||||
dataIndex : 'deviceos',
|
||||
header : _('Device OS'),
|
||||
hidden : true,
|
||||
renderer : Ext.util.Format.htmlEncode
|
||||
},{
|
||||
dataIndex : 'devicefriendlyname',
|
||||
header : _('Device Info'),
|
||||
hidden : true,
|
||||
renderer : Ext.util.Format.htmlEncode
|
||||
},{
|
||||
dataIndex : 'firstsynctime',
|
||||
header : _('First Sync time'),
|
||||
hidden : true,
|
||||
renderer : Ext.util.Format.htmlEncode
|
||||
}],
|
||||
buttons : [{
|
||||
text : _('Wipe Device'),
|
||||
ref : '../../../wipeBtn',
|
||||
handler : this.onWipeBtn,
|
||||
scope : this
|
||||
},{
|
||||
text : _('Full resync'),
|
||||
ref : '../../../resyncBtn',
|
||||
handler : this.onFullResync,
|
||||
scope : this
|
||||
},{
|
||||
text : _('Remove device'),
|
||||
ref : '../../../removeBtn',
|
||||
handler : this.onRemoveDevice,
|
||||
scope : this
|
||||
},{
|
||||
text : _('Refresh'),
|
||||
ref : '../../../refresh',
|
||||
handler : this.onRefresh,
|
||||
scope : this
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
});
|
||||
Zarafa.plugins.mdm.settings.MDMSettingsWidget.superclass.constructor.call(this, config);
|
||||
},
|
||||
|
||||
/**
|
||||
* Function which handles the click event on the "Wipe Device" button, displays
|
||||
* a MessageBox for the user to confirm the wipe action. The wipe action is
|
||||
* handled by the onWipeDevice function.
|
||||
*/
|
||||
onWipeBtn : function()
|
||||
{
|
||||
var msgbox = Ext.MessageBox.show({
|
||||
title: _('Kopano WebApp'),
|
||||
msg: _('Do you really want to wipe your device?\n Enter your password to confirm.'),
|
||||
inputType :'password',
|
||||
icon: Ext.MessageBox.WARNING,
|
||||
buttons: Ext.MessageBox.YESNO,
|
||||
fn: this.onWipeDevice,
|
||||
prompt: true,
|
||||
scope: this.deviceGrid
|
||||
});
|
||||
|
||||
// ExtJS does not support a password field.
|
||||
msgbox.getDialog().body.child('input').dom.type = 'password';
|
||||
},
|
||||
|
||||
/**
|
||||
* Function which handles the confirmation button in the "wipe device" messagebox.
|
||||
* Sends an wipe request to PHP for the selected device in the grid.
|
||||
*
|
||||
* @param {Ext.Button} button button from the messagebox
|
||||
* @param {String} password user password
|
||||
*/
|
||||
onWipeDevice : function(button, password)
|
||||
{
|
||||
if (button === 'yes') {
|
||||
var selectionModel = this.getSelectionModel();
|
||||
var record = selectionModel.getSelected();
|
||||
if (record) {
|
||||
container.getRequest().singleRequest(
|
||||
'pluginmdmmodule',
|
||||
'wipe',
|
||||
{ 'deviceid' : record.get('entryid'), 'password': password },
|
||||
new Zarafa.plugins.mdm.data.MDMResponseHandler()
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Function which handles the click event on the "Full resync" button, sends a
|
||||
* full resync request to PHP.
|
||||
*/
|
||||
onFullResync : function()
|
||||
{
|
||||
var selectionModel = this.deviceGrid.getSelectionModel();
|
||||
var record = selectionModel.getSelected();
|
||||
if(record) {
|
||||
container.getRequest().singleRequest(
|
||||
'pluginmdmmodule',
|
||||
'resync',
|
||||
{ 'deviceid' : record.get('entryid') },
|
||||
new Zarafa.plugins.mdm.data.MDMResponseHandler()
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove all state data for a device, essentially resyncing it.
|
||||
*/
|
||||
onRemoveDevice : function()
|
||||
{
|
||||
var selectionModel = this.deviceGrid.getSelectionModel();
|
||||
var record = selectionModel.getSelected();
|
||||
if(record) {
|
||||
container.getRequest().singleRequest(
|
||||
'pluginmdmmodule',
|
||||
'remove',
|
||||
{ 'deviceid' : record.get('entryid') },
|
||||
new Zarafa.plugins.mdm.data.MDMResponseHandler({
|
||||
successCallback : this.removeDone.createDelegate(this, [record], true)
|
||||
})
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Callback function triggers when device was successfully removed from the z-push server.
|
||||
* we have to remove that device from {@link Zarafa.plugins.mdm.data.MDMDeviceStore store}.
|
||||
* @param {Zarafa.plugins.mdm.data.MDMDeviceRecord} record {@link Zarafa.core.data.IPMRecord record} object
|
||||
*/
|
||||
removeDone : function(record)
|
||||
{
|
||||
record.getStore().remove(record);
|
||||
},
|
||||
|
||||
/**
|
||||
* Function which refreshes the store records from the server.
|
||||
*/
|
||||
onRefresh : function()
|
||||
{
|
||||
this.deviceGrid.getStore().load();
|
||||
}
|
||||
});
|
||||
|
||||
Ext.reg('Zarafa.plugins.mdm.mdmsettingswidget', Zarafa.plugins.mdm.settings.MDMSettingsWidget);
|
23
js/ui/Renderers.js
Normal file
23
js/ui/Renderers.js
Normal file
@ -0,0 +1,23 @@
|
||||
Ext.namespace('Zarafa.plugins.mdm.ui');
|
||||
|
||||
/**
|
||||
* @class Zarafa.plugins.mdm.ui.Renderers
|
||||
* Methods of this object can be used as renderers for grid panels, to render
|
||||
* cells in custom format according to data type
|
||||
* @singleton
|
||||
*/
|
||||
Zarafa.plugins.mdm.ui.Renderers = {
|
||||
|
||||
/**
|
||||
* Render the Provisioning Status.
|
||||
*
|
||||
* @param {Object} value The data value for the cell.
|
||||
* @param {Object} p An object with metadata
|
||||
* @param {Ext.data.record} record The {Ext.data.Record} from which the data was extracted.
|
||||
* @return {String} The formatted string
|
||||
*/
|
||||
provisioningStatus : function(value, p, record)
|
||||
{
|
||||
return Zarafa.plugins.mdm.data.ProvisioningStatus.getDisplayName(parseInt(value));
|
||||
}
|
||||
}
|
41
manifest.xml
Executable file
41
manifest.xml
Executable file
@ -0,0 +1,41 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE plugin SYSTEM "manifest.dtd">
|
||||
<plugin version="2">
|
||||
<info>
|
||||
<version>0.1</version>
|
||||
<name>mdm</name>
|
||||
<title>Mobile Device Management</title>
|
||||
<author>Kopano</author>
|
||||
<authorURL>http://www.kopano.com</authorURL>
|
||||
<description>Mobile Device Management plugin</description>
|
||||
</info>
|
||||
<config>
|
||||
<configfile>config.php</configfile>
|
||||
</config>
|
||||
<components>
|
||||
<component>
|
||||
<files>
|
||||
<server>
|
||||
<serverfile>php/plugin.mdm.php</serverfile>
|
||||
<serverfile type="module" module="pluginmdmmodule">php/class.pluginmdmmodule.php</serverfile>
|
||||
</server>
|
||||
<client>
|
||||
<clientfile load="release">js/mdm.js</clientfile>
|
||||
<clientfile load="debug">js/mdm-debug.js</clientfile>
|
||||
<clientfile load="source">js/MDM.js</clientfile>
|
||||
<clientfile load="source">js/data/MDMResponseHandler.js</clientfile>
|
||||
<clientfile load="source">js/data/MDMDeviceRecord.js</clientfile>
|
||||
<clientfile load="source">js/data/JsonDeviceReader.js</clientfile>
|
||||
<clientfile load="source">js/data/MDMDeviceStore.js</clientfile>
|
||||
<clientfile load="source">js/data/ProvisioningStatus.js</clientfile>
|
||||
<clientfile load="source">js/settings/MDMSettingsWidget.js</clientfile>
|
||||
<clientfile load="source">js/settings/MDMSettingsCategory.js</clientfile>
|
||||
<clientfile load="source">js/ui/Renderers.js</clientfile>
|
||||
</client>
|
||||
<resources>
|
||||
<resourcefile load="release">resources/css/mdm.css</resourcefile>
|
||||
</resources>
|
||||
</files>
|
||||
</component>
|
||||
</components>
|
||||
</plugin>
|
207
php/class.pluginmdmmodule.php
Executable file
207
php/class.pluginmdmmodule.php
Executable file
@ -0,0 +1,207 @@
|
||||
<?php
|
||||
|
||||
// For backward compatibility we must check if the file exists
|
||||
if ( file_exists(BASE_PATH . 'server/includes/core/class.encryptionstore.php') ) {
|
||||
require_once(BASE_PATH . 'server/includes/core/class.encryptionstore.php');
|
||||
}
|
||||
|
||||
/**
|
||||
* PluginMDMModule Module
|
||||
*/
|
||||
class PluginMDMModule extends Module
|
||||
{
|
||||
private $server = '';
|
||||
private $username = '';
|
||||
private $password = '';
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param int $id unique id.
|
||||
* @param array $data list of all actions.
|
||||
*/
|
||||
function PluginMDMModule($id, $data)
|
||||
{
|
||||
parent::Module($id, $data);
|
||||
|
||||
$this->server = (PLUGIN_MDM_SERVER_SSL ? 'https://' : 'http://') . PLUGIN_MDM_SERVER;
|
||||
|
||||
// For backward compatibility we will check if the Encryption store exists. If not,
|
||||
// we will fall back to the old way of retrieving the password from the session.
|
||||
if ( class_exists('EncryptionStore') ) {
|
||||
|
||||
// Get the username and password from the Encryption store
|
||||
$encryptionStore = EncryptionStore::getInstance();
|
||||
$this->username = $encryptionStore->get('username');
|
||||
$this->password = $encryptionStore->get('password');
|
||||
} else {
|
||||
$this->username = $GLOBALS['mapisession']->getUserName();
|
||||
|
||||
$this->password = $_SESSION['password'];
|
||||
if(function_exists('openssl_decrypt')) {
|
||||
// In PHP 5.3.3 the iv parameter was added
|
||||
if(version_compare(phpversion(), "5.3.3", "<")) {
|
||||
$this->password = openssl_decrypt($this->password, "des-ede3-cbc", PASSWORD_KEY, 0);
|
||||
} else {
|
||||
$this->password = openssl_decrypt($this->password, "des-ede3-cbc", PASSWORD_KEY, 0, PASSWORD_IV);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->url = $this->server .'/Microsoft-Server-ActiveSync?Cmd=WebserviceDevice&DeviceId=webservice&DeviceType=webservice&User=' . $this->username;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to setup a client.
|
||||
*/
|
||||
function getSoapClient()
|
||||
{
|
||||
return new SoapClient(null, array(
|
||||
'location' => $this->url,
|
||||
'uri' => $this->server,
|
||||
'trace' => 1,
|
||||
'login' => $this->username,
|
||||
'password' => $this->password
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Function which calls the soap call to do a full resync
|
||||
* @param int $deviceid of phone which has to be resynced
|
||||
* @return json $response object contains the response of the soap request from Z-Push
|
||||
*/
|
||||
function resyncDevice($deviceid)
|
||||
{
|
||||
$client = $this->getSoapClient();
|
||||
return $client->ResyncDevice($deviceid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function which calls the wipeDevice soap call
|
||||
* @param int $deviceid of phone which has to be wiped
|
||||
* @param string $password user password
|
||||
* @return json $response object contains the response of the soap request from Z-Push
|
||||
*/
|
||||
function wipeDevice($deviceid, $password)
|
||||
{
|
||||
if ($password == $this->password) {
|
||||
$client = $this->getSoapClient();
|
||||
return $client->WipeDevice($deviceid);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* function which calls the ListDeviceDetails soap call
|
||||
* @return array $response array contains a list of devices connected to the users account
|
||||
*/
|
||||
function getDevices()
|
||||
{
|
||||
$client = $this->getSoapClient();
|
||||
return $client->ListDevicesDetails();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
function which calls the wipeDevice soap call
|
||||
* @param int $deviceid of phone which has to be wiped
|
||||
* @return json $response object contains the response of the soap request from Z-Push
|
||||
*/
|
||||
function removeDevice($deviceid)
|
||||
{
|
||||
$client = $this->getSoapClient();
|
||||
return $client->RemoveDevice($deviceid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes all the actions in the $data variable.
|
||||
* @return boolean true on success of false on fialure.
|
||||
*/
|
||||
function execute()
|
||||
{
|
||||
foreach($this->data as $actionType => $actionData)
|
||||
{
|
||||
if(isset($actionType)) {
|
||||
try {
|
||||
switch($actionType)
|
||||
{
|
||||
case 'wipe':
|
||||
$this->wipeDevice($actionData['deviceid'], $actionData['password']);
|
||||
$this->addActionData('wipe', array(
|
||||
'type' => 3,
|
||||
'wipe' => $this->wipeDevice($actionData['deviceid'], $actionData['password'])
|
||||
));
|
||||
$GLOBALS['bus']->addData($this->getResponseData());
|
||||
break;
|
||||
case 'resync':
|
||||
$this->addActionData('resync', array(
|
||||
'type' => 3,
|
||||
'resync' => $this->resyncDevice($actionData['deviceid'])
|
||||
));
|
||||
$GLOBALS['bus']->addData($this->getResponseData());
|
||||
break;
|
||||
case 'remove':
|
||||
$this->addActionData('remove', array(
|
||||
'type' => 3,
|
||||
'remove' => $this->removeDevice($actionData['deviceid'])
|
||||
));
|
||||
$GLOBALS['bus']->addData($this->getResponseData());
|
||||
break;
|
||||
case 'list':
|
||||
$items = array();
|
||||
$date['page'] = array();
|
||||
|
||||
$rawData = $this->getDevices();
|
||||
foreach($rawData as $device){
|
||||
$device = $device->data;
|
||||
$item = array();
|
||||
$item['entryid'] = $device['deviceid'];
|
||||
$item['changed'] = $device['changed'];
|
||||
$item['deviceos'] = $device['deviceos'];
|
||||
$item['devicefriendlyname'] = $device['devicefriendlyname'];
|
||||
$item['devicetype'] = $device['devicetype'];
|
||||
$item['devicemodel'] = $device['devicemodel'];
|
||||
$item['hierarchyuuid'] = $device['hierarchyuuid'];
|
||||
$item['firstsynctime'] = $device['firstsynctime'];
|
||||
$item['lastupdatetime'] = $device['lastupdatetime'];
|
||||
$item['wipestatus'] = $device['wipestatus'];
|
||||
$item['useragent'] = $device['useragent'];
|
||||
$item['domain'] = $device['domain'];
|
||||
array_push($items, array('props' => $item));
|
||||
}
|
||||
$data['page']['start'] = 0;
|
||||
$data['page']['rowcount'] = count($rawData);
|
||||
$data['page']['totalrowcount'] = $data['page']['rowcount'];
|
||||
$data = array_merge($data, array('item' => $items));
|
||||
|
||||
$this->addActionData('list', $data);
|
||||
$GLOBALS['bus']->addData($this->getResponseData());
|
||||
break;
|
||||
default:
|
||||
$this->handleUnknownActionType($actionType);
|
||||
}
|
||||
} catch (SoapFault $fault) {
|
||||
$display_message = _('Something went wrong.');
|
||||
if ($fault->faultcode === 'HTTP') {
|
||||
if ($fault->getMessage() === "Unauthorized") {
|
||||
$display_message = _('Unable to connect to Z-Push Server. Unauthorized.');
|
||||
}
|
||||
if ($fault->getMessage() === "Could not connect to host") {
|
||||
$display_message = _('Unable to connect to Z-Push Server. Could not connect to host.');
|
||||
}
|
||||
if ($fault->getMessage() === "Not Found") {
|
||||
$display_message = _('Unable to connect to Z-Push Server. Not found.');
|
||||
}
|
||||
} else if ($fault->faultcode === "ERROR") {
|
||||
$display_message = _('Device ID could not be found');
|
||||
}
|
||||
$this->sendFeedback(false, array("type" => ERROR_GENERAL, "info" => array('display_message' => $display_message)));
|
||||
}
|
||||
catch (Exception $e) {
|
||||
$this->sendFeedback(true, array("type" => ERROR_GENERAL, "info" => array('display_message' => _('Something went wrong'))));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
?>
|
48
php/plugin.mdm.php
Executable file
48
php/plugin.mdm.php
Executable file
@ -0,0 +1,48 @@
|
||||
<?php
|
||||
/**
|
||||
* Handles plugin registration.
|
||||
*/
|
||||
class PluginMDM extends Plugin {
|
||||
// Constructor
|
||||
function PluginMDM(){}
|
||||
|
||||
/**
|
||||
* Called to initialize the plugin and register for hooks.
|
||||
*/
|
||||
function init(){
|
||||
$this->registerHook('server.core.settings.init.before');
|
||||
}
|
||||
|
||||
/**
|
||||
* Function is executed when a hook is triggered by the PluginManager
|
||||
* @param String $eventID Identifier of the hook
|
||||
* @param Array $data Reference to the data of the triggered hook
|
||||
*/
|
||||
function execute($eventID, &$data){
|
||||
switch($eventID){
|
||||
case 'server.core.settings.init.before':
|
||||
$this->onBeforeSettingsInit($data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the core Settings class is initialized and ready to accept sysadmin default
|
||||
* settings. Registers the sysadmin defaults for the StatsLogging plugin.
|
||||
* @param Array $data Reference to the data of the triggered hook
|
||||
*/
|
||||
function onBeforeSettingsInit(&$data){
|
||||
$data['settingsObj']->addSysAdminDefaults(Array(
|
||||
'zarafa' => Array(
|
||||
'v1' => Array(
|
||||
'plugins' => Array(
|
||||
'mdm' => Array(
|
||||
'enable' => PLUGIN_MDM_USER_DEFAULT_ENABLE_MDM,
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
));
|
||||
}
|
||||
}
|
||||
?>
|
3
resources/css/mdm.css
Executable file
3
resources/css/mdm.css
Executable file
@ -0,0 +1,3 @@
|
||||
.icon_mdm_settings {
|
||||
background-image:url(../icons/mdm_icon.png) !important;
|
||||
}
|
BIN
resources/icons/mdm_icon.png
Executable file
BIN
resources/icons/mdm_icon.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 262 B |
BIN
resources/icons/mdm_icon.xcf
Executable file
BIN
resources/icons/mdm_icon.xcf
Executable file
Binary file not shown.
Loading…
Reference in New Issue
Block a user