Index: univention-cupsadmin =================================================================== --- univention-cupsadmin (revision 4816) +++ univention-cupsadmin (working copy) @@ -50,11 +50,14 @@ # argv[0] should be something like .../univention-cups... Cut # univention-cups from it -if os.path.basename(cmd)=="univention-cups-enable" or os.path.basename(cmd)=="univention-cups-disable": - cmd=os.path.basename(cmd).replace("univention-cups-", "/usr/bin/cups") -else: - cmd=os.path.basename(cmd).replace("univention-cups-", "/usr/sbin/cups") +# +# cupsenable and -disable aren't located in /usr/bin anymore +#if os.path.basename(cmd)=="univention-cups-enable" or os.path.basename(cmd)=="univention-cups-disable": +# cmd=os.path.basename(cmd).replace("univention-cups-", "/usr/bin/cups") +#else: +cmd=os.path.basename(cmd).replace("univention-cups-", "/usr/sbin/cups") + # check if target executable exists if not(os.path.exists(cmd)): print("Target executable %s does not exist. Exiting."%cmd) Index: debian/control =================================================================== --- debian/control (revision 4816) +++ debian/control (working copy) @@ -74,3 +74,18 @@ integrated, directory driven solution for managing corporate environments. For more information about UCS, refer to: http://www.univention.de/ + +Package: univention-management-console-module-printers +Architecture: all +Depends: ${misc:Depends}, + univention-directory-manager-tools (>> 7.0.147), + univention-management-console-server, + univention-printserver (= ${source:Version}) +Description: UMC module for printer administration + This package contains the UMC module for the administration + of configured printers. + . + It is part of Univention Corporate Server (UCS), an + integrated, directory driven solution for managing + corporate environments. For more information about UCS, + refer to: http://www.univention.de/ Index: debian/rules =================================================================== --- debian/rules (revision 4816) +++ debian/rules (working copy) @@ -37,6 +37,7 @@ msgfmt --check -o $@ $< override_dh_auto_build: $(MO_FILES) + dh-umc-module-build dh_auto_build override_dh_auto_test: Index: 35univention-management-console-module-printers.inst =================================================================== --- 35univention-management-console-module-printers.inst (revision 0) +++ 35univention-management-console-module-printers.inst (revision 0) @@ -0,0 +1,49 @@ +#!/bin/sh +# -*- coding: utf-8 -*- +# +# Univention Management Console Module top +# join script +# +# Copyright 2011 Univention GmbH +# +# http://www.univention.de/ +# +# All rights reserved. +# +# The source code of this program is made available +# under the terms of the GNU Affero General Public License version 3 +# (GNU AGPL V3) as published by the Free Software Foundation. +# +# Binary versions of this program provided by Univention to you as +# well as other copyrighted, protected or trademarked materials like +# Logos, graphics, fonts, specific documentations and configurations, +# cryptographic keys etc. are subject to a license agreement between +# you and Univention and not subject to the GNU AGPL V3. +# +# In the case you use this program under the terms of the GNU AGPL V3, +# the program is provided in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public +# License with the Debian GNU/Linux or Univention distribution in file +# /usr/share/common-licenses/AGPL-3; if not, see +# . + +VERSION=1 + +. /usr/share/univention-join/joinscripthelper.lib +. /usr/share/univention-lib/umc.sh + +joinscript_init + +umc_init +umc_operation_create "printers-all" "Printer Administration" "" "printers/*" +umc_policy_append "default-umc-all" "printers-all" + +joinscript_save_current_version + +exit 0 + + Index: umc/python/printers/de.po =================================================================== --- umc/python/printers/de.po (revision 0) +++ umc/python/printers/de.po (revision 0) @@ -0,0 +1,14 @@ +# This file is auto-generated by the dh-umc tools and should not be edited! +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: univention-management-console-module-printers\n" +"Report-Msgid-Bugs-To: packages@univention.de\n" +"POT-Creation-Date: 2011-11-07 12:45+0100\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" Index: umc/python/printers/__init__.py =================================================================== --- umc/python/printers/__init__.py (revision 0) +++ umc/python/printers/__init__.py (revision 0) @@ -0,0 +1,366 @@ +#!/usr/bin/python2.6 +# -*- coding: utf-8 -*- +# +# Univention Management Console +# module: updater +# +# Copyright 2011 Univention GmbH +# +# http://www.univention.de/ +# +# All rights reserved. +# +# The source code of this program is made available +# under the terms of the GNU Affero General Public License version 3 +# (GNU AGPL V3) as published by the Free Software Foundation. +# +# Binary versions of this program provided by Univention to you as +# well as other copyrighted, protected or trademarked materials like +# Logos, graphics, fonts, specific documentations and configurations, +# cryptographic keys etc. are subject to a license agreement between +# you and Univention and not subject to the GNU AGPL V3. +# +# In the case you use this program under the terms of the GNU AGPL V3, +# the program is provided in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public +# License with the Debian GNU/Linux or Univention distribution in file +# /usr/share/common-licenses/AGPL-3; if not, see +# . + +import pprint +import subprocess +import univention.management.console as umc +import univention.management.console.modules as umcm +import univention.config_registry + +from fnmatch import * +import re +import string +import subprocess + +from univention.management.console.log import MODULE +from univention.management.console.protocol.definitions import * + +_ = umc.Translation('univention-management-console-module-printers').translate + +class Instance(umcm.Base): + + def init(self): + + self.ucr = univention.config_registry.ConfigRegistry() + self.ucr.load() + + self._hostname = self.ucr.get('hostname') + + + def list_printers(self,request): + """ Lists the printers for the overview grid. """ + + # ----------- DEBUG ----------------- + MODULE.info("printers/query invoked with:") + pp = pprint.PrettyPrinter(indent=4) + st = pp.pformat(request.options).split("\n") + for s in st: + MODULE.info(" << %s" % s) + # ----------------------------------- + + key = request.options.get('key','printer') + pattern = request.options.get('pattern','*') + + quota = self._quota_enabled() # we need it later + + result = [] + plist = self._list_printers() + for element in plist: + try: + printer = element['printer'] + data = self._printer_details(printer) + for field in data: + element[field] = data[field] + # filter according to query + if fnmatch(element[key],pattern): + if printer in quota: + element['quota'] = quota[printer] + else: + element['quota'] = False + result.append(element) + except: + pass + + # ---------- DEBUG -------------- + MODULE.info("printers/query returns:") + pp = pprint.PrettyPrinter(indent=4) + st = '' + if len(result) > 5: + tmp = result[0:5] + MODULE.info(" >> %d entries, first 5 are:" % len(result)) + st = pp.pformat(tmp).split("\n") + else: + st = pp.pformat(result).split("\n") + for s in st: + MODULE.info(" >> %s" % s) + # -------------------------------- + + self.finished(request.id,result) + + def get(self,request): + """ gets detail data for one printer. """ + + # ----------- DEBUG ----------------- + MODULE.info("printers/get invoked with:") + pp = pprint.PrettyPrinter(indent=4) + st = pp.pformat(request.options).split("\n") + for s in st: + MODULE.info(" << %s" % s) + # ----------------------------------- + + printer = request.options.get('printer','') + result = self._printer_details(printer) + result['printer'] = printer + result['status'] = self._printer_status(printer) + result['quota'] = self._quota_enabled(printer) + + # ---------- DEBUG -------------- + MODULE.info("printers/get returns:") + pp = pprint.PrettyPrinter(indent=4) + st = pp.pformat(result).split("\n") + for s in st: + MODULE.info(" >> %s" % s) + # -------------------------------- + + self.finished(request.id,result) + + def list_jobs(self,request): + """ returns list of jobs for one printer. """ + + # ----------- DEBUG ----------------- + MODULE.info("printers/jobs/query invoked with:") + pp = pprint.PrettyPrinter(indent=4) + st = pp.pformat(request.options).split("\n") + for s in st: + MODULE.info(" << %s" % s) + # ----------------------------------- + + result = self._job_list(request.options.get('printer','')) + + # ---------- DEBUG -------------- + MODULE.info("printers/jobs/query returns:") + pp = pprint.PrettyPrinter(indent=4) + st = '' + if len(result) > 5: + tmp = result[0:5] + MODULE.info(" >> %d entries, first 5 are:" % len(result)) + st = pp.pformat(tmp).split("\n") + else: + st = pp.pformat(result).split("\n") + for s in st: + MODULE.info(" >> %s" % s) + # -------------------------------- + + self.finished(request.id,result) + + def list_quota(self,request): + """ lists all quota entries related to this printer. """ + + # fill a dummy result table. + printer = request.options.get('printer','') + result = [] + + self.finished(request.id,result) + + def enable(self,request): + """ can enable or disable a printer, depending on args. + returns empty string on success, else error message. + """ + + # ----------- DEBUG ----------------- + MODULE.info("printers/enable invoked with:") + pp = pprint.PrettyPrinter(indent=4) + st = pp.pformat(request.options).split("\n") + for s in st: + MODULE.info(" << %s" % s) + # ----------------------------------- + + printer = request.options.get('printer','') + on = request.options.get('on',False) + + result = self._enable_printer(printer,on) + + # ---------- DEBUG -------------- + MODULE.info("printers/enable returns:") + pp = pprint.PrettyPrinter(indent=4) + st = pp.pformat(result).split("\n") + for s in st: + MODULE.info(" >> %s" % s) + # -------------------------------- + + self.finished(request.id, result) + + def cancel(self,request): + """ cancels one or more print jobs. Job IDs are passed + as an array that can be directly passed on to the + _shell_command() method + """ + + # ----------- DEBUG ----------------- + MODULE.info("printers/jobs/cancel invoked with:") + pp = pprint.PrettyPrinter(indent=4) + st = pp.pformat(request.options).split("\n") + for s in st: + MODULE.info(" << %s" % s) + # ----------------------------------- + + jobs = request.options['jobs'] + printer = request.options.get('printer','') + result = self._cancel_jobs(printer,jobs) + + # ---------- DEBUG -------------- + MODULE.info("printers/jobs/cancel returns:") + pp = pprint.PrettyPrinter(indent=4) + st = pp.pformat(result).split("\n") + for s in st: + MODULE.info(" >> %s" % s) + # -------------------------------- + + self.finished(request.id, result) + + + + # ----------------------- Internal functions ------------------------- + + def _job_list(self,printer): + """ lists jobs for a given printer, directly suitable for the grid """ + + # *** NOTE *** we don't set language to 'neutral' since it is useful + # to get localized date/time strings. + + result = [] + (stdout,stderr,status) = self._shell_command(['/usr/bin/lpstat','-o',printer]) + expr = re.compile('\s*(\S+)\s+(\S+)\s+(\d+)\s*(.*?)$') + if status == 0: + for line in stdout.split("\n"): + mobj = expr.match(line) + if mobj: + entry = { + 'job': mobj.group(1), + 'owner': mobj.group(2), + 'size': mobj.group(3), + 'date': mobj.group(4) + } + result.append(entry) + return result + + def _list_printers(self): + """ returns a list of printers, along with their 'enabled' status. """ + + result = [] + expr = re.compile('printer\s+(\S+)\s.*?(\S+abled)') + (stdout,stderr,status) = self._shell_command(['/usr/bin/lpstat','-p'],{'LANG':'C'}) + if status == 0: + for line in stdout.split("\n"): + mobj = expr.match(line) + if mobj: + entry = { 'printer' : mobj.group(1), 'status': mobj.group(2) } + result.append(entry) + return result + + def _printer_status(self,printer): + """ returns the 'enabled' status of a printer """ + + (stdout,stderr,status) = self._shell_command(['/usr/bin/lpstat','-p',printer],{'LANG':'C'}) + if status == 0: + if ' enabled ' in stdout: + return 'enabled' + if ' disabled ' in stdout: + return 'disabled' + return 'unknown' + + def _printer_details(self,printer): + """ returns as much as possible details about a printer. """ + + result = {} + expr = re.compile('\s+([^\s\:]+)\:\s*(.*?)$') + (stdout,stderr,status) = self._shell_command(['/usr/bin/lpstat','-l','-p',printer],{'LANG':'C'}) + if status == 0: + for line in stdout.split("\n"): + mobj = expr.match(line) + if mobj: + result[mobj.group(1).lower()] = mobj.group(2) + result['server'] = self._hostname + return result + + def _enable_printer(self,printer,on): + """ internal function that enables/disables a printer. + returns empty string or error message. + """ + + cmd = 'univention-cups-enable' if on else 'univention-cups-disable' + (stdout,stderr,status) = self._shell_command([cmd,printer]) + + if status: + return stderr + + # Q: What do these tools return if the cups command being called returns with error? + # A: They return zero, the exit code meant for success. + # + # Q: Which is the channel where these tools print the ERROR message? + # A: On STDOUT, as the name suggests. + # + # Q: What do these tools print on success? + # A: Two newlines, instead of nothing. + if re.search('\S',stdout): + return stdout + + return '' + + def _quota_enabled(self,printer=None): + """ returns a dictionary with printer names and their 'quota active' status. + if printer is specified, returns only quota status for this printer. + """ + + result = {} + expr = re.compile('device for (\S+)\:\s*(\S+)$') + (stdout,stderr,status) = self._shell_command(['/usr/bin/lpstat','-v'],{'LANG':'C'}) + if status == 0: + for line in stdout.split("\n"): + match = expr.match(line) + if match: + quota = False + if match.group(2).startswith('cupspykota'): + quota = True + result[match.group(1)] = quota + # No printer specified: return the whole list. + if printer == None: + return result + + # Printer specified: return its quota value or False if not found. + if printer in result: + return result[printer] + return False + + def _cancel_jobs(self,printer,jobs): + """ internal function that cancels a list of jobs. + returns empty string or error message. + """ + + args = ['/usr/bin/cancel','-U','%s$' % self._hostname] + for job in jobs: + args.append(job) + args.append(printer) + (stdout,stderr,status) = self._shell_command(args) + + if status: + return stderr + return '' + + def _shell_command(self,args,env=None): + + proc = subprocess.Popen(args=args, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env) + outputs = proc.communicate() + + return (outputs[0],outputs[1],proc.returncode) + \ No newline at end of file Index: umc/printers.xml =================================================================== --- umc/printers.xml (revision 0) +++ umc/printers.xml (revision 0) @@ -0,0 +1,35 @@ + + + + Printer Administration + Manage defined printers + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Index: umc/de.po =================================================================== --- umc/de.po (revision 0) +++ umc/de.po (revision 0) @@ -0,0 +1,20 @@ +# This file is auto-generated by the dh-umc tools and should not be edited! +msgid "" +msgstr "" +"Project-Id-Version: univention-management-console-module-printers\n" +"Report-Msgid-Bugs-To: packages@univention.de\n" +"POT-Creation-Date: Mon, 07 Nov 2011 12:45:12 +0100\n" +"PO-Revision-Date: \n" +"Last-Translator: Univention GmbH \n" +"Language-Team: Univention GmbH \n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +msgid "Manage defined printers" +msgstr "Drucker verwalten" + +msgid "Printer Administration" +msgstr "Druckerverwaltung" + Index: umc/syntax/printers.xml =================================================================== --- umc/syntax/printers.xml (revision 0) +++ umc/syntax/printers.xml (revision 0) @@ -0,0 +1,5 @@ + + + + + Index: umc/icons/50x50/printing.png =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Property changes on: umc/icons/50x50/printing.png ___________________________________________________________________ Added: svn:mime-type + application/octet-stream Index: umc/icons/16x16/printing.png =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Property changes on: umc/icons/16x16/printing.png ___________________________________________________________________ Added: svn:mime-type + application/octet-stream Index: umc/icons/scalable/printing.svgz =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Property changes on: umc/icons/scalable/printing.svgz ___________________________________________________________________ Added: svn:mime-type + application/octet-stream Index: umc/js/printers.js =================================================================== --- umc/js/printers.js (revision 0) +++ umc/js/printers.js (revision 0) @@ -0,0 +1,129 @@ +/*global console MyError dojo dojox dijit umc window */ + +dojo.provide("umc.modules.printers"); + +dojo.require("umc.i18n"); +dojo.require("umc.dialog"); +dojo.require("umc.widgets.ConfirmDialog"); +dojo.require("umc.tools"); + +// ----------- sub pages --------------- +dojo.require("umc.modules._printers.OverviewPage"); +dojo.require("umc.modules._printers.DetailPage"); +dojo.require("umc.modules._printers.QuotaPage"); + +dojo.declare("umc.modules.printers", [ + umc.widgets.Module, + umc.i18n.Mixin + ], +{ + + i18nClass: 'umc.modules.printers', + + _quota_from_page: '', // remembers the page from which the 'editQuota' was called + + buildRendering: function() { + + this.inherited(arguments); + + this._pages = { + 'overview': new umc.modules._printers.OverviewPage(), + 'detail': new umc.modules._printers.DetailPage(), + 'quota': new umc.modules._printers.QuotaPage() + }; + + // forIn behaves like forEach just for dicts :) ... important it checks for hasOwnProperty! + umc.tools.forIn(this._pages, function(iname, ipage) { + this.addChild(ipage); + }, this); + + // -------------- Events for page switching ---------------- + + dojo.connect(this._pages['overview'],'openDetail',dojo.hitch(this,function(args) { + this._switch_page('detail',args); + })); + + dojo.connect(this._pages['overview'],'editQuota',dojo.hitch(this, function(args) { + this._quota_from_page = 'overview'; + this._switch_page('quota',args); + })); + + dojo.connect(this._pages['detail'],'editQuota',dojo.hitch(this, function(args) { + this._quota_from_page = 'detail'; + this._switch_page('quota',args); + })); + + dojo.connect(this._pages['detail'],'closeDetail',dojo.hitch(this, function(args) { + this._switch_page('overview',args); + })); + + dojo.connect(this._pages['quota'],'closeQuota',dojo.hitch(this, function(args) { + this._switch_page(this._quota_from_page,args); + })); + + // ------------- work events: printer management --------------- + + dojo.connect(this._pages['overview'],'managePrinter',dojo.hitch(this, function(printer,func,callback) { + this._manage_printer(printer,func,callback); + })); + dojo.connect(this._pages['detail'],'managePrinter',dojo.hitch(this, function(printer,func,callback) { + this._manage_printer(printer,func,callback); + })); + }, + + startup: function() { + + this.inherited(arguments); + + this._switch_page('overview'); + }, + + _switch_page: function(name, args) { + + if ((args) && (typeof (this._pages[name].setArgs) == 'function')) + { + this._pages[name].setArgs(args); + } + + this.selectChild(this._pages[name]); + + }, + + // Most management functions can be called from overview or detail view, so we write + // the functions here. + _manage_printer: function(printer,func,callback) { + + var cmd = ''; + var args = {}; + switch(func) + { + case 'activate': + cmd = 'printers/enable'; + args = { printer: printer, on: true }; + break; + case 'deactivate': + cmd = 'printers/enable'; + args = { printer: printer, on: false }; + break; + } + if (cmd) + { + umc.tools.umcpCommand(cmd,args).then( + dojo.hitch(this, function(data) { + if (data.result.length) + { + callback(false,data.result); + } + else + { + callback(true); + } + }), + dojo.hitch(this, function(data) { + callback(false,data.result); + }) + ); + } + } + +}); Index: umc/js/de.po =================================================================== --- umc/js/de.po (revision 0) +++ umc/js/de.po (revision 0) @@ -0,0 +1,208 @@ +# This file is auto-generated by the dh-umc tools and should not be edited! +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: univention-management-console-module-printers\n" +"Report-Msgid-Bugs-To: packages@univention.de\n" +"POT-Creation-Date: 2011-11-09 17:57+0100\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: umc/js/_printers/DetailPage.js:59 umc/js/_printers/OverviewPage.js:133 +msgid "Activate" +msgstr "Aktivieren" + +#: umc/js/_printers/DetailPage.js:60 +msgid "Activate this printer" +msgstr "diesen Drucker aktivieren" + +#: umc/js/_printers/QuotaPage.js:88 +msgid "Back" +msgstr "zurück" + +#: umc/js/_printers/DetailPage.js:151 +msgid "Back to overview" +msgstr "Zurück zur Übersicht" + +#: umc/js/_printers/DetailPage.js:129 +msgid "Cancel" +msgstr "Abbrechen" + +#: umc/js/_printers/DetailPage.js:130 +msgid "Cancel this job/these jobs" +msgstr "Diesen Druckauftrag (oder mehrere) abbrechen" + +#: umc/js/_printers/QuotaPage.js:25 +msgid "Current quota records for printer" +msgstr "Aktuelle Quota-Einträge für diesen Drucker" + +#: umc/js/_printers/DetailPage.js:71 umc/js/_printers/OverviewPage.js:151 +msgid "Deactivate" +msgstr "Deaktivieren" + +#: umc/js/_printers/DetailPage.js:72 +msgid "Deactivate this printer" +msgstr "diesen Drucker deaktivieren" + +#: umc/js/_printers/DetailPage.js:232 umc/js/_printers/OverviewPage.js:53 +#: umc/js/_printers/OverviewPage.js:118 +msgid "Description" +msgstr "Beschreibung" + +#: umc/js/_printers/DetailPage.js:222 +msgid "Details for printer {printer}" +msgstr "Details für Drucker {printer}" + +#: umc/js/_printers/QuotaPage.js:81 +msgid "Edit" +msgstr "" + +#: umc/js/_printers/DetailPage.js:83 umc/js/_printers/OverviewPage.js:169 +msgid "Edit quota" +msgstr "Quota bearbeiten" + +#: umc/js/_printers/DetailPage.js:84 +msgid "Edit quota related to this printer" +msgstr "Quota-Einträge für diesen Drucker bearbeiten" + +#: umc/js/_printers/QuotaPage.js:63 +msgid "Hard limit" +msgstr "Hard limit" + +#: umc/js/_printers/DetailPage.js:110 +msgid "Job" +msgstr "Druckauftrag" + +#: umc/js/_printers/QuotaPage.js:67 +msgid "Lifetime page counter" +msgstr "Seitenzähler" + +#: umc/js/_printers/DetailPage.js:231 umc/js/_printers/OverviewPage.js:54 +#: umc/js/_printers/OverviewPage.js:114 +msgid "Location" +msgstr "Ort" + +#: umc/js/_printers/DetailPage.js:114 +msgid "Owner" +msgstr "Eigentümer" + +#: umc/js/_printers/QuotaPage.js:55 +msgid "Pages used" +msgstr "gedruckte Seiten" + +#: umc/js/_printers/OverviewPage.js:61 +msgid "Pattern" +msgstr "Suchbegriff" + +#: umc/js/_printers/OverviewPage.js:84 +msgid "Printer" +msgstr "Drucker" + +#: umc/js/_printers/OverviewPage.js:29 umc/js/_printers/OverviewPage.js:40 +msgid "Printer administration" +msgstr "Druckerverwaltung" + +#: umc/js/_printers/DetailPage.js:27 umc/js/_printers/DetailPage.js:38 +msgid "Printer details" +msgstr "Druckerdetails" + +#: umc/js/_printers/OverviewPage.js:52 +msgid "Printer name" +msgstr "Druckername" + +#: umc/js/_printers/QuotaPage.js:26 umc/js/_printers/QuotaPage.js:37 +msgid "Printer quota" +msgstr "Druckername" + +#: umc/js/_printers/DetailPage.js:229 umc/js/_printers/OverviewPage.js:103 +msgid "Quota" +msgstr "Quota" + +#: umc/js/_printers/QuotaPage.js:131 +#, fuzzy +msgid "Quota entries for printer {printer}" +msgstr "Details für Drucker {printer}" + +#: umc/js/_printers/QuotaPage.js:96 +#, fuzzy +msgid "Refresh" +msgstr "Job-Liste aktualisieren" + +#: umc/js/_printers/DetailPage.js:159 +msgid "Refresh job list" +msgstr "Job-Liste aktualisieren" + +#: umc/js/_printers/OverviewPage.js:180 +msgid "Refresh printer list" +msgstr "Drucker-Liste aktualisieren" + +#: umc/js/_printers/QuotaPage.js:74 +msgid "Reset user quota" +msgstr "Quota für diesen Nutzer zurücksetzen" + +#: umc/js/_printers/OverviewPage.js:50 +msgid "Search key" +msgstr "Suchbegriff" + +#: umc/js/_printers/DetailPage.js:224 umc/js/_printers/OverviewPage.js:80 +msgid "Server" +msgstr "Server" + +#: umc/js/_printers/DetailPage.js:118 +msgid "Size" +msgstr "Größe" + +#: umc/js/_printers/QuotaPage.js:59 +msgid "Soft limit" +msgstr "Soft limit" + +#: umc/js/_printers/DetailPage.js:225 umc/js/_printers/OverviewPage.js:88 +msgid "Status" +msgstr "Status" + +#: umc/js/_printers/DetailPage.js:122 +msgid "Submitted at" +msgstr "beauftragt" + +#: umc/js/_printers/OverviewPage.js:28 +msgid "This module lets you manage the printers defined on your machine" +msgstr "" +"In diesem Modul können Sie die Drucker verwalten, die auf Ihrer Maschine " +"definiert sind." + +#: umc/js/_printers/QuotaPage.js:51 +msgid "User" +msgstr "Nutzer" + +#: umc/js/_printers/OverviewPage.js:125 +msgid "View details" +msgstr "Details ansehen" + +#: umc/js/_printers/DetailPage.js:26 +msgid "" +"You see the details of this printer and its print jobs. You can activate/" +"deactivate the printer, edit its quota definitions if quota is enabled, and " +"cancel print jobs." +msgstr "" +"Sie sehen die Details des Druckers sowie seine aktuellen Druckaufträge. Sie " +"können den Drucker aktivieren/deaktivieren, Quota-Einträge verwalten und " +"Druckaufträge abbrechen." + +#: umc/js/_printers/DetailPage.js:218 umc/js/_printers/DetailPage.js:229 +#: umc/js/_printers/OverviewPage.js:95 umc/js/_printers/OverviewPage.js:107 +msgid "active" +msgstr "aktiv" + +#: umc/js/_printers/DetailPage.js:219 umc/js/_printers/OverviewPage.js:96 +#: umc/js/_printers/OverviewPage.js:109 +msgid "inactive" +msgstr "inaktiv" + +#: umc/js/_printers/DetailPage.js:215 umc/js/_printers/OverviewPage.js:98 +msgid "unknown" +msgstr "unbekannt" Index: umc/js/_printers/QuotaPage.js =================================================================== --- umc/js/_printers/QuotaPage.js (revision 0) +++ umc/js/_printers/QuotaPage.js (revision 0) @@ -0,0 +1,140 @@ +/*global console MyError dojo dojox dijit umc */ + +dojo.provide("umc.modules._printers.QuotaPage"); + +dojo.require("umc.i18n"); +dojo.require("umc.dialog"); +dojo.require("umc.store"); +dojo.require("umc.tools"); + +dojo.require("umc.widgets.Page"); +dojo.require("umc.widgets.Grid"); +dojo.require("umc.widgets.Form"); + +dojo.declare("umc.modules._printers.QuotaPage", +[ + umc.widgets.Page, + umc.i18n.Mixin +], { + + i18nClass: 'umc.modules.printers', + + postMixInProperties: function() { + + dojo.mixin(this,{ + helpText: this._("Current quota records for printer"), + headerText: this._("Printer quota") + }); + + this.inherited(arguments); + }, + + buildRendering: function() { + + this.inherited(arguments); + + var pane = new umc.widgets.ExpandingTitlePane({ + title: this._("Printer quota") + }); + this.addChild(pane); + + this._head = new umc.widgets.Text({ + region: 'top', + content: '', + style: 'padding-bottom:1em;font-size:115%;' + }); + pane.addChild(this._head); + + var columns = [ + { + name: 'user', + label: this._("User") + }, + { + name: 'used', + label: this._("Pages used") + }, + { + name: 'soft', + label: this._("Soft limit") + }, + { + name: 'hard', + label: this._("Hard limit") + }, + { + name: 'total', + label: this._("Lifetime page counter") + } + ]; + + var actions = [ + { + name: 'clear', + label: this._("Reset user quota"), + callback: dojo.hitch(this, function(ids) { + // TODO do something useful here + }) + }, + { + name: 'edit', + label: this._("Edit"), + callback: dojo.hitch(this, function(ids) { + // TODO do something useful here + }) + }, + { + name: 'back', + label: this._("Back"), + isContextAction: false, + callback: dojo.hitch(this, function() { + this.closeQuota(); + }) + }, + { + name: 'refresh', + label: this._("Refresh"), + isContextAction: false, + callback: dojo.hitch(this, function() { + this._refresh_view(); + }) + } + ]; + + this._grid = new umc.widgets.Grid({ + region: 'center', + columns: columns, + actions: actions, + moduleStore: umc.store.getModuleStore('user','printers/quota') + }); + pane.addChild(this._grid); + + }, + + // Calling page passes args here. Arg is here the printer ID. + setArgs: function(args) { + + this._printer_id = args; + this._refresh_view(); + }, + + onHide: function() { + // force clean state + this._head.set('content',''); // clear header text + this._grid.filter(); // clear grid data + }, + + // called when the page is shown, but can equally be called + // on a manual or automatic refresh. + _refresh_view: function() { + + this._head.set('content',dojo.replace(this._("Quota entries for printer {printer}"),{printer:this._printer_id})); + + // read current quota list + this._grid.filter({printer:this._printer_id}); + }, + + // main module listens here to return to the detail page + closeQuota: function(args) { + } +}); Index: umc/js/_printers/DetailPage.js =================================================================== --- umc/js/_printers/DetailPage.js (revision 0) +++ umc/js/_printers/DetailPage.js (revision 0) @@ -0,0 +1,297 @@ +/*global console MyError dojo dojox dijit umc */ + +dojo.provide("umc.modules._printers.DetailPage"); + +dojo.require("umc.i18n"); +dojo.require("umc.dialog"); +dojo.require("umc.store"); +dojo.require("umc.tools"); + +dojo.require("umc.widgets.Page"); +dojo.require("umc.widgets.Grid"); +dojo.require("umc.widgets.Form"); + +dojo.declare("umc.modules._printers.DetailPage", +[ + umc.widgets.Page, + umc.i18n.Mixin +], { + + i18nClass: 'umc.modules.printers', + _printer_id: '', + + postMixInProperties: function() { + + dojo.mixin(this,{ + helpText: this._("You see the details of this printer and its print jobs. You can activate/deactivate the printer, edit its quota definitions if quota is enabled, and cancel print jobs."), + headerText: this._("Printer details") + }); + + this.inherited(arguments); + }, + + buildRendering: function() { + + this.inherited(arguments); + + var pane = new umc.widgets.ExpandingTitlePane({ + title: this._("Printer details") + }); + this.addChild(pane); + + var f_widgets = [ + { + name: 'message', + type: 'Text', + content: '
 
 
 
 
 ', + style: 'padding-bottom:.5em;' // force bottom distance to the buttons + } + ]; + + var f_layout = [ + [ 'message' ], + [ 'activate', 'deactivate', 'editquota', 'submit' ] + ]; + + var f_buttons = [ + { + name: 'activate', + label: this._("Activate"), + title: this._("Activate this printer"), + onClick: dojo.hitch(this, function() { + this.managePrinter(this._printer_id,'activate', + dojo.hitch(this, function(success,message) { + this._manage_callback(success,message); + }) + ); + }) + }, + { + name: 'deactivate', + label: this._("Deactivate"), + title: this._("Deactivate this printer"), + onClick: dojo.hitch(this, function() { + this.managePrinter(this._printer_id,'deactivate', + dojo.hitch(this, function(success,message) { + this._manage_callback(success,message); + }) + ); + }) + }, + { + name: 'editquota', + label: this._("Edit quota"), + title: this._("Edit quota related to this printer"), + onClick: dojo.hitch(this, function() { + this.editQuota(this._printer_id); + }) + }, + // only to stop the Form class from adding a hidden submit button into + // an additional row, thus mangling my layout... + { + name: 'submit', + label: 'nothing' + } + ]; + + // we make this a form so we can add buttons + this._head = new umc.widgets.Form({ + region: 'top', + widgets: f_widgets, + buttons: f_buttons, + layout: f_layout, + onSubmit: function() {} // don't want to have any kind of submit here! + }); + pane.addChild(this._head); + + var columns = [ + { + name: 'job', + label: this._("Job") + }, + { + name: 'owner', + label: this._("Owner") + }, + { + name: 'size', + label: this._("Size") + }, + { + name: 'date', + label: this._("Submitted at") + } + ]; + + var actions = [ + { + name: 'cancel', + label: this._("Cancel"), + title: this._("Cancel this job/these jobs"), + isMultiAction: true, + isStandardAction: true, + callback: dojo.hitch(this, function(ids) { + umc.tools.umcpCommand('printers/jobs/cancel',{jobs: ids, printer:this._printer_id}).then( + dojo.hitch(this,function(data) { + if (data.result) + { + umc.dialog.alert(data.result); + } + this._refresh_view(); + }), + dojo.hitch(this,function(data) { + umc.tools.alert(data.message); + this._refresh_view(); + }) + ); + }) + }, + { + name: 'back', + label: this._("Back to overview"), + isContextAction: false, + callback: dojo.hitch(this, function() { + this.closeDetail(); + }) + }, + { + name: 'refresh', + label: this._("Refresh job list"), + isContextAction: false, + callback: dojo.hitch(this, function() { + this._refresh_view(); + }) + } + ]; + + this._grid = new umc.widgets.Grid({ + region: 'center', + columns: columns, + actions: actions, + moduleStore: umc.store.getModuleStore('job','printers/jobs') + }); + pane.addChild(this._grid); + + }, + + // Overview page passes args here. Arg is here the printer ID. + setArgs: function(args) { + + this._printer_id = args; + this._refresh_view(); + }, + + // no matter where we came from: if the page is to be shown we + // have to refresh all data elements. + onShow: function() { + this._refresh_view(); + }, + + // called when the page is shown, but can equally be called + // on a manual or automatic refresh. + _refresh_view: function() { + + // if the function is called before setArgs has given us a valid printer name + // then we should simply do nothing. + if (! this._printer_id) + { + return; + } + + umc.tools.umcpCommand('printers/get',{printer:this._printer_id}).then( + dojo.hitch(this, function(data) { + + // Yes I know, I should have this done by the layout capabilities of + // the Form class... but given the fact that this is only an informative + // overview message I've decided to wrap it into a single 'Text' element, + // containing a

..

and a . + var res = data.result; + // styles + var st_h = 'font-size:115%;text-decoration:underline;'; // header line + var st_l = 'text-align:right;padding-left:1em;'; // left column + var st_r = 'padding-left:.5em;'; // right column + + // status text must be translated in our official wording... + var status = this._("unknown"); + switch(res['status']) + { + case 'enabled': status = this._("active"); break; + case 'disabled':status = this._("inactive"); break; + } + + var txt = "

" + dojo.replace(this._("Details for printer {printer}"),res) + '

'; + txt += "
\n"; + txt += "\n"; + txt += "\n"; + // show this only if quota is enabled + if (res['quota']) + { + txt += "\n"; + } + txt += "\n"; + txt += "\n"; + txt += "
" + this._("Server") + ":" + res['server'] + "
" + this._("Status") + ":" + status + "
" + this._("Quota") + ":" + this._("active") + "
" + this._("Location") + ":" + res['location'] + "
" + this._("Description") + ":" + res['description'] + "
\n"; + + this._head.getWidget('message').set('content',txt); + + // show/hide corresponding buttons + + this._show_button('activate',res['status'] == 'disabled'); + this._show_button('deactivate',res['status'] == 'enabled'); + this._show_button('editquota',res['quota']); + this._show_button('submit',false); // always invisible. + + this.layout(); // whenever you change a non-center region of a BorderLayout... + }), + dojo.hitch(this, function(data) { + this._grid.filter(); // clears stale grid data + }) + ); + + // read job list + this._grid.filter({printer:this._printer_id}); + }, + + _show_button: function(button,on) { + + try + { + dojo.toggleClass(this._head._buttons[button].domNode,'dijitHidden',!on); + } + catch(ex) + { + console.error("show_button(" + button + "," + on + "): " + ex.message); + } + }, + + _manage_callback: function(success,message) { + + if (success) + { + this._refresh_view(); + } + else + { + umc.dialog.alert(message); + } + }, + + // main module listens here, to carry out direct printer + // management functions. + managePrinter: function(printer,func,arg) { + }, + + // main module listens here to return to the overview. + // args are passed back to the Overview page. + closeDetail: function(args) { + // force clean state + this._head.getWidget('message').set('content','
 
 
 
 
 '); // six empty lines + this._grid.filter(); + }, + + // main module listens here to open the quota page. + editQuota: function(args) { + } + + +}); Index: umc/js/_printers/OverviewPage.js =================================================================== --- umc/js/_printers/OverviewPage.js (revision 0) +++ umc/js/_printers/OverviewPage.js (revision 0) @@ -0,0 +1,252 @@ +/*global console MyError dojo dojox dijit umc */ + +dojo.provide("umc.modules._printers.OverviewPage"); + +dojo.require("umc.i18n"); +dojo.require("umc.dialog"); +dojo.require("umc.tools"); +dojo.require("umc.store"); + +dojo.require("umc.widgets.Page"); +dojo.require("umc.widgets.Grid"); +dojo.require("umc.widgets.Form"); +dojo.require("umc.widgets.SearchForm"); +dojo.require("umc.widgets.ExpandingTitlePane"); + +dojo.declare("umc.modules._printers.OverviewPage", +[ + umc.widgets.Page, + umc.i18n.Mixin +], { + + i18nClass: 'umc.modules.printers', + _last_filter: { key: 'printer', pattern: '*' }, + + postMixInProperties: function() { + + dojo.mixin(this,{ + helpText: this._("This module lets you manage the printers defined on your machine"), + headerText: this._("Printer administration") + }); + + this.inherited(arguments); + }, + + buildRendering: function() { + + this.inherited(arguments); + + var pane = new umc.widgets.ExpandingTitlePane({ + title: this._("Printer administration") + }); + this.addChild(pane); + + this._form = new umc.widgets.SearchForm({ + region: 'top', + widgets: [ + { + name: 'key', + type: 'ComboBox', + label: this._("Search key"), + staticValues: [ + { id: 'printer', label: this._("Printer name")}, + { id: 'description', label: this._("Description")}, + { id: 'location', label: this._("Location") } + ], + sortStaticValues: false + }, + { + name: 'pattern', + type: 'TextBox', + label: this._("Pattern"), + value: '*' + } + ], + layout: [ + [ 'key', 'pattern', 'submit' ] + ], + onSearch: dojo.hitch(this, function(values) { + this._enable_search_button(false); + this._last_filter = values; // save for easy refresh + this._grid.filter(values); + }) + }); + this._enable_search_button(false); + pane.addChild(this._form); + + var columns = [ + { + name: 'server', + label: this._("Server") + }, + { + name: 'printer', + label: this._("Printer") + }, + { + name: 'status', + label: this._("Status"), + // 'enabled'/'disabled' are kind of keywords, just as they're returned + // from cups if invoked without locale (LANG=C). + // Our wording for this is 'active'/'inactive'. + formatter: dojo.hitch(this,function(value) { + switch(value) + { + case 'enabled': return this._("active"); + case 'disabled': return this._("inactive"); + } + return this._("unknown"); + }) + }, + { + name: 'quota', + label: this._("Quota"), + formatter: dojo.hitch(this,function(value) { + if (value) // only true or false? + { + return this._("active"); + } + return this._("inactive"); + }) + }, + { + name: 'location', + label: this._("Location") + }, + { + name: 'description', + label: this._("Description") + } + ]; + + var actions = [ + { + name: 'open', + label: this._("View details"), + callback: dojo.hitch(this,function(id,values) { + // 2.4 uses the printer ID as key property, so we do that as well. + this.openDetail(id[0]); + }) + }, + { + name: 'activate', + label: this._("Activate"), + callback: dojo.hitch(this, function(ids) { + // no multi action for now, but who knows... + for (var p in ids) + { + this.managePrinter(ids[p],'activate', + dojo.hitch(this, function(success,message) { + this._manage_callback(success,message); + }) + ); + } + }), + canExecute: dojo.hitch(this, function(values) { + return (values['status'] == 'disabled'); + }) + }, + { + name: 'deactivate', + label: this._("Deactivate"), + callback: dojo.hitch(this, function(ids) { + // no multi action for now, but who knows... + for (var p in ids) + { + this.managePrinter(ids[p],'deactivate', + dojo.hitch(this, function(success,message) { + this._manage_callback(success,message); + }) + ); + } + }), + canExecute: dojo.hitch(this, function(values) { + return (values['status'] == 'enabled'); + }) + }, + { + name: 'editquota', + label: this._("Edit quota"), + isStandardAction: false, + callback: dojo.hitch(this,function(ids) { + this.editQuota(ids[0]); + }), + canExecute: dojo.hitch(this,function(values) { + return (values['quota']); // true or false + }) + }, + { + name: 'refresh', + label: this._("Refresh printer list"), + isContextAction: false, + callback: dojo.hitch(this, function() { + this._refresh_view(); + }) + } + ]; + + this._grid = new umc.widgets.Grid({ + columns: columns, + region: 'center', + actions: actions, + defaultAction: 'open', + moduleStore: umc.store.getModuleStore('printer','printers'), + // fill grid on first open + query: {key:'printer', pattern: '*'}, + onFilterDone: dojo.hitch(this, function(success) { + this._enable_search_button(true); + }) + }); + pane.addChild(this._grid); + + + }, + + _enable_search_button: function(on) { + this._form._buttons['submit'].setDisabled(! on); + }, + + // refreshes the grid. can be called manually (pressing the refresh button) + // or automatically (as response to the managePrinter() result) + _refresh_view: function() { + this._grid.filter(this._last_filter); + }, + + // will be called with the result of 'managePrinter' + _manage_callback: function(success,message) { + + if (success) + { + this._refresh_view(); + } + else + { + umc.dialog.alert(message); + } + }, + + // when we come back from any kind of detail view that + // could have invoked some actions... refresh our view. + onShow: function() { + this._refresh_view(); + }, + + // DetailPage gives results back here. + setArgs: function(args) { + }, + + // main module listens here, to carry out direct printer + // management functions. + managePrinter: function(printer,func,callback) { + }, + + // main module listens here, to switch to the detail view. + // args can propagate the id of the printer to show + openDetail: function(args) { + }, + + // main module listens here to open the quota page. + editQuota: function(args) { + } + +});