|
31 |
# /usr/share/common-licenses/AGPL-3; if not, see |
31 |
# /usr/share/common-licenses/AGPL-3; if not, see |
32 |
# <http://www.gnu.org/licenses/>. |
32 |
# <http://www.gnu.org/licenses/>. |
33 |
|
33 |
|
34 |
import pprint |
34 |
import re |
35 |
import subprocess |
35 |
import subprocess |
36 |
import os |
36 |
import lxml.html |
37 |
import univention.management.console as umc |
|
|
38 |
import univention.management.console.modules as umcm |
39 |
from univention.management.console.modules import UMC_CommandError |
40 |
|
37 |
|
41 |
import univention.config_registry |
38 |
from univention.lib.i18n import Translation |
|
|
39 |
|
42 |
import univention.admin.uldap |
40 |
import univention.admin.uldap |
43 |
|
41 |
|
44 |
import re |
42 |
from univention.management.console.base import Base |
45 |
|
|
|
46 |
from univention.management.console.log import MODULE |
43 |
from univention.management.console.log import MODULE |
47 |
from univention.management.console.protocol.definitions import * |
44 |
from univention.management.console.config import ucr |
|
|
45 |
from univention.management.console.modules import UMC_Error |
48 |
from univention.management.console.modules.decorators import simple_response, log, sanitize |
46 |
from univention.management.console.modules.decorators import simple_response, log, sanitize |
49 |
from univention.management.console.modules.sanitizers import PatternSanitizer, ChoicesSanitizer |
47 |
from univention.management.console.modules.sanitizers import PatternSanitizer, ChoicesSanitizer |
50 |
|
48 |
|
51 |
_ = umc.Translation('univention-management-console-module-printers').translate |
49 |
_ = Translation('univention-management-console-module-printers').translate |
52 |
|
50 |
|
53 |
class Instance(umcm.Base): |
51 |
class Instance(Base): |
54 |
|
52 |
|
55 |
def init(self): |
53 |
def init(self): |
|
|
54 |
self._hostname = ucr.get('hostname') |
56 |
|
55 |
|
57 |
self.ucr = univention.config_registry.ConfigRegistry() |
|
|
58 |
self.ucr.load() |
59 |
|
60 |
self._hostname = self.ucr.get('hostname') |
61 |
|
62 |
@sanitize(pattern=PatternSanitizer(default='.*'), key=ChoicesSanitizer(choices=['printer', 'description', 'location'], required=True)) |
56 |
@sanitize(pattern=PatternSanitizer(default='.*'), key=ChoicesSanitizer(choices=['printer', 'description', 'location'], required=True)) |
63 |
@simple_response |
57 |
@simple_response |
64 |
def list_printers(self, key, pattern): |
58 |
def list_printers(self, key, pattern): |
|
105 |
""" lists all quota entries related to this printer. """ |
99 |
""" lists all quota entries related to this printer. """ |
106 |
|
100 |
|
107 |
result = [] |
101 |
result = [] |
|
|
102 |
status = None |
108 |
|
103 |
|
109 |
if not os.path.exists('/usr/bin/pkusers'): |
104 |
try: |
110 |
raise UMC_CommandError(_('The print quota settings are currently disabled. Please install the package univention-printquota to enable them.')) |
105 |
from pykota.tool import PyKotaTool |
|
|
106 |
from pykota import reporter |
107 |
from pykota.storages.pgstorage import PGError |
108 |
except ImportError: |
109 |
raise UMC_Error(_('The print quota settings are currently disabled. Please install the package univention-printquota to enable them.')) |
111 |
|
110 |
|
112 |
(stdout, stderr, status) = self._shell_command(['/usr/bin/pkusers', '--list'], {'LANG':'C'}) |
111 |
reportTool = PyKotaTool() |
113 |
users = [] |
112 |
try: |
114 |
expr = re.compile('^\s*(.*?)\s+\-\s\<') |
113 |
reportTool.deferredInit() |
115 |
if status == 0: |
114 |
printers = reportTool.storage.getMatchingPrinters(printer) |
116 |
for line in stdout.split("\n"): |
115 |
reportingtool = reporter.openReporter(reportTool, 'html', printers, '*', 0) |
117 |
match = expr.match(line) |
116 |
status = reportingtool.generateReport() |
118 |
if match: |
117 |
except PGError as exc: |
119 |
users.append(match.group(1)) |
118 |
MODULE.error('Cannot connect to postgres: %s' % (exc,)) |
|
|
119 |
raise UMC_Error(_('The connection to the print quota postgres database failed. Please make sure the postgres service is running and reachable.')) |
120 |
finally: |
121 |
reportTool.regainPriv() |
120 |
|
122 |
|
121 |
result = [] |
123 |
if status: |
122 |
for user in users: |
124 |
tree = lxml.html.fromstring(status) |
123 |
if not os.path.exists('/usr/bin/repykota'): |
125 |
table = tree.find_class('pykotatable') |
124 |
raise UMC_CommandError(_('The print quota settings are currently disabled. Please install the package univention-printquota to enable them.')) |
126 |
for i in table: |
|
|
127 |
for a in i.iterchildren(tag='tr'): |
128 |
data = list() |
129 |
for b in a.iterchildren(tag='td'): |
130 |
data.append(b.text_content().strip()) |
131 |
if data and len(data) >= 11: |
132 |
user = data[0] |
133 |
#limitby = data[1] |
134 |
#overcharge = data[2] |
135 |
used = data[3] |
136 |
soft = data[4] |
137 |
hard = data[5] |
138 |
#balance = data[6] |
139 |
#grace = data[7] |
140 |
total = data[8] |
141 |
#paid = data[9] |
142 |
#warn = data[10] |
143 |
result.append(dict( |
144 |
user=user, |
145 |
used=used, |
146 |
soft=soft, |
147 |
hard=hard, |
148 |
total=total, |
149 |
)) |
125 |
|
150 |
|
126 |
(stdout, stderr, status) = self._shell_command(['/usr/bin/repykota', '-P', printer, user], {'LANG':'C'}) |
|
|
127 |
if status == 0: |
128 |
for line in stdout.split("\n"): |
129 |
data = line[16:].split() # ignore possibly truncated user name |
130 |
if len(data) >= 7: |
131 |
ok = True |
132 |
for n in (2, 3,4, len(data)-3): |
133 |
if not data[n].isdigit(): |
134 |
ok = False |
135 |
if ok: |
136 |
MODULE.info(" -> user='%s' used=%s soft=%s hard=%s total=%s" % (user, data[2], data[3], data[4], data[len(data)-3])) |
137 |
entry = { |
138 |
'user': user, |
139 |
'used': data[2], |
140 |
'soft': data[3], |
141 |
'hard': data[4], |
142 |
'total': data[len(data)-3] |
143 |
} |
144 |
result.append(entry) |
145 |
return result |
151 |
return result |
146 |
|
152 |
|
147 |
@simple_response |
153 |
@simple_response |
|
179 |
|
185 |
|
180 |
return self._cancel_jobs(printer, jobs) |
186 |
return self._cancel_jobs(printer, jobs) |
181 |
|
187 |
|
182 |
|
|
|
183 |
@simple_response |
188 |
@simple_response |
184 |
@log |
189 |
@log |
185 |
def set_quota(self, printer='', user='', soft=0, hard=0): |
190 |
def set_quota(self, printer='', user='', soft=0, hard=0): |
|
324 |
cmd.append(user) |
329 |
cmd.append(user) |
325 |
(stdout, stderr, status) = self._shell_command(cmd, {'LANG':'C'}) |
330 |
(stdout, stderr, status) = self._shell_command(cmd, {'LANG':'C'}) |
326 |
|
331 |
|
327 |
if status or len(stderr): |
332 |
if status or stderr: |
328 |
return stderr |
333 |
return stderr |
329 |
|
334 |
|
330 |
return '' |
335 |
return '' |
|
350 |
return result |
355 |
return result |
351 |
|
356 |
|
352 |
# Printer specified: return its quota value or False if not found. |
357 |
# Printer specified: return its quota value or False if not found. |
353 |
if printer in result: |
358 |
return result.get(printer, False) |
354 |
return result[printer] |
|
|
355 |
return False |
356 |
|
359 |
|
357 |
def _cancel_jobs(self, printer, jobs): |
360 |
def _cancel_jobs(self, printer, jobs): |
358 |
""" internal function that cancels a list of jobs. |
361 |
""" internal function that cancels a list of jobs. |
|
375 |
outputs = proc.communicate() |
378 |
outputs = proc.communicate() |
376 |
|
379 |
|
377 |
return (outputs[0], outputs[1], proc.returncode) |
380 |
return (outputs[0], outputs[1], proc.returncode) |
378 |
|
|
|