Changeset 2054 for pykota/trunk
- Timestamp:
- 02/13/05 23:02:29 (20 years ago)
- Location:
- pykota/trunk
- Files:
-
- 23 modified
Legend:
- Unmodified
- Added
- Removed
-
pykota/trunk/bin/cupspykota
r2028 r2054 24 24 # 25 25 # $Log$ 26 # Revision 1.85 2005/02/13 22:02:28 jalet 27 # Big database structure changes. Upgrade script is now included as well as 28 # the new LDAP schema. 29 # Introduction of the -o | --overcharge command line option to edpykota. 30 # The output of repykota is more complete, but doesn't fit in 80 columns anymore. 31 # Introduction of the new 'maxdenybanners' directive. 32 # 26 33 # Revision 1.84 2005/01/17 08:44:23 jalet 27 34 # Modified copyright years … … 501 508 accountbanner = self.config.getAccountBanner(printer.Name) 502 509 if accountbanner in ["ENDING", "NONE"] : 503 banner = self.startingBanner(printer.Name) 504 if banner : 505 self.logdebug("Printing starting banner before accounting begins.") 506 self.handleData(banner) 510 if (action == 'DENY') and (userpquota.WarnCount < self.config.getMaxDenyBanners()) : 511 self.printInfo(_("Banner won't be printed : maximum number of deny banners reached."), "warn") 512 else : 513 if action == 'DENY' : 514 userpquota.warn() # increments the warning counter 515 self.exportUserInfo(userpquota) 516 banner = self.startingBanner(printer.Name) 517 if banner : 518 self.logdebug("Printing starting banner before accounting begins.") 519 self.handleData(banner) 507 520 508 521 self.printMoreInfo(user, printer, _("Job accounting begins.")) … … 511 524 # handle starting banner pages during accounting 512 525 if accountbanner in ["STARTING", "BOTH"] : 513 banner = self.startingBanner(printer.Name) 514 if banner : 515 self.logdebug("Printing starting banner during accounting.") 516 self.handleData(banner) 517 if self.accounter.isSoftware : 518 bannersize += 1 # TODO : fix this by passing the banner's content through PDLAnalyzer 526 if (action == 'DENY') and (userpquota.WarnCount < self.config.getMaxDenyBanners()) : 527 self.printInfo(_("Banner won't be printed : maximum number of deny banners reached."), "warn") 528 else : 529 if action == 'DENY' : 530 userpquota.warn() # increments the warning counter 531 self.exportUserInfo(userpquota) 532 banner = self.startingBanner(printer.Name) 533 if banner : 534 self.logdebug("Printing starting banner during accounting.") 535 self.handleData(banner) 536 if self.accounter.isSoftware : 537 bannersize += 1 # TODO : fix this by passing the banner's content through PDLAnalyzer 519 538 else : 520 539 action = "ALLOW" … … 536 555 # handle ending banner pages during accounting 537 556 if accountbanner in ["ENDING", "BOTH"] : 538 banner = self.endingBanner(printer.Name) 539 if banner : 540 self.logdebug("Printing ending banner during accounting.") 541 self.handleData(banner) 542 if self.accounter.isSoftware : 543 bannersize += 1 # TODO : fix this by passing the banner's content through PDLAnalyzer 557 if (action == 'DENY') and (userpquota.WarnCount < self.config.getMaxDenyBanners()) : 558 self.printInfo(_("Banner won't be printed : maximum number of deny banners reached."), "warn") 559 else : 560 if action == 'DENY' : 561 userpquota.warn() # increments the warning counter 562 self.exportUserInfo(userpquota) 563 banner = self.endingBanner(printer.Name) 564 if banner : 565 self.logdebug("Printing ending banner during accounting.") 566 self.handleData(banner) 567 if self.accounter.isSoftware : 568 bannersize += 1 # TODO : fix this by passing the banner's content through PDLAnalyzer 544 569 545 570 # stops accounting. … … 575 600 # handle ending banner pages after accounting ends 576 601 if accountbanner in ["STARTING", "NONE"] : 577 banner = self.endingBanner(printer.Name) 578 if banner : 579 self.logdebug("Printing ending banner after accounting ends.") 580 self.handleData(banner) 581 602 if (action == 'DENY') and (userpquota.WarnCount < self.config.getMaxDenyBanners()) : 603 self.printInfo(_("Banner won't be printed : maximum number of deny banners reached."), "warn") 604 else : 605 if action == 'DENY' : 606 userpquota.warn() # increments the warning counter 607 self.exportUserInfo(userpquota) 608 banner = self.endingBanner(printer.Name) 609 if banner : 610 self.logdebug("Printing ending banner after accounting ends.") 611 self.handleData(banner) 612 582 613 # Launches the post hook 583 614 self.posthook(userpquota) … … 823 854 try : 824 855 status = subprocess.wait() 825 except OSError : # already dead 856 except OSError : # already dead : TODO : detect when abnormal 826 857 status = 0 827 858 if os.WIFEXITED(status) : -
pykota/trunk/bin/edpykota
r2036 r2054 24 24 # 25 25 # $Log$ 26 # Revision 1.87 2005/02/13 22:02:28 jalet 27 # Big database structure changes. Upgrade script is now included as well as 28 # the new LDAP schema. 29 # Introduction of the -o | --overcharge command line option to edpykota. 30 # The output of repykota is more complete, but doesn't fit in 80 columns anymore. 31 # Introduction of the new 'maxdenybanners' directive. 32 # 26 33 # Revision 1.86 2005/01/21 14:40:01 jalet 27 34 # edpykota's --delete command line tool doesn't use "*" as its default argument … … 337 344 If both are to be set, separate them with a comma. 338 345 Floating point values are allowed. 346 347 -o | --overcharge f Sets the overcharging factor applied to the user 348 when computing the cost of a print job. Positive or 349 negative floating point values are allowed, 350 this allows you to do some really creative 351 things like giving money to an user whenever 352 he prints. The number of pages in a print job 353 is not modified by this coefficient, only the 354 cost of the job for a particular user. 355 Only users have a coefficient. 339 356 340 357 -i | --ingroups g1[,g2...] Puts the users into each of the groups … … 480 497 When printing either on hplj1 or hplj2, print quota will also be 481 498 checked and accounted for on virtual printers Laser and HP. 499 500 $ edpykota --overcharge 2.5 poorstudent 501 502 This will overcharge the poorstudent user by a factor of 2.5. 503 504 $ edpykota --overcharge -1 jerome 505 506 User jerome will actually earn money whenever he prints. 507 508 $ edpykota --overcharge 0 boss 509 510 User boss can print at will, it won't cost him anything because the 511 cost of each print job will be multiplied by zero before charging 512 his account. 482 513 483 514 This program is free software; you can redistribute it and/or modify … … 532 563 (softlimit, hardlimit) = (hardlimit, softlimit) 533 564 565 overcharge = options["overcharge"] 566 if overcharge : 567 try : 568 overcharge = float(overcharge.strip()) 569 except (ValueError, AttributeError) : 570 raise PyKotaToolError, _("Invalid overcharge value %s") % options["overcharge"] 571 534 572 balance = options["balance"] 535 573 if balance : … … 710 748 entrypquota.setUsage(used) 711 749 750 if overcharge is not None : 751 if changed[entry.Name].get("overcharge") is None : 752 entry.setOverChargeFactor(overcharge) 753 changed[entry.Name]["overcharge"] = overcharge 754 712 755 if balance : 713 756 if changed[entry.Name].get("balance") is None : … … 742 785 "printer" : "*", \ 743 786 } 744 short_options = "vhd c:l:b:i:naugrp:P:S:H:G:RU:"745 long_options = ["help", "version", " charge=", "delete", "limitby=", "balance=", "ingroups=", "noquota", "add", "users", "groups", "reset", "hardreset", "prototype=", "printer=", "softlimit=", "hardlimit=", "pgroups=", "used="]787 short_options = "vhdo:c:l:b:i:naugrp:P:S:H:G:RU:" 788 long_options = ["help", "version", "overcharge=", "charge=", "delete", "limitby=", "balance=", "ingroups=", "noquota", "add", "users", "groups", "reset", "hardreset", "prototype=", "printer=", "softlimit=", "hardlimit=", "pgroups=", "used="] 746 789 747 790 # Initializes the command line tool … … 771 814 options["hardreset"] = options["R"] or options["hardreset"] 772 815 options["used"] = options["U"] or options["used"] 816 options["overcharge"] = options["o"] or options["overcharge"] 773 817 774 818 if options["help"] : … … 784 828 elif options["noquota"] and (options["prototype"] or options["hardlimit"] or options["softlimit"]) : 785 829 raise PyKotaToolError, _("incompatible options, see help.") 786 elif options["groups"] and (options["balance"] or options["ingroups"] or options["used"] ) :830 elif options["groups"] and (options["balance"] or options["ingroups"] or options["used"] or options["overcharge"]) : 787 831 raise PyKotaToolError, _("incompatible options, see help.") 788 832 else : -
pykota/trunk/conf/pykota.conf.sample
r2028 r2054 610 610 # printers, or "localhost" if not defined or not 611 611 # meaningful. 612 # PYKOTAWARNCOUNT : the number of times the user was forbidden to print but a banner 613 # page was still printed on the current printer. 614 # PYKOTAOVERCHARGE : user's overcharging factor. 615 # 612 616 613 617 # PreHook : gets executed after being sure the user, printer and user quota … … 657 661 # accountbanner: Both 658 662 663 # Maximal number of times the banner will still be printed if 664 # the user is forbidden to print. 665 # 666 # NB : CUPS ONLY FOR NOW ! 667 # 668 # This option can be set either globally or on a per printer basis. 669 # Allowed values are 0 or any positive integer. 670 # Default value is 0, which means that the banner won't be printed 671 # at all if the user is forbidden to print. 672 maxdenybanners: 0 673 659 674 # StartingBanner : if defined will print a banner before the rest of the job 660 675 # is printed. The argument can be a printable file, or an executable file. -
pykota/trunk/FAQ
r2047 r2054 19 19 that all debug messages for PyKota will go to syslog's 20 20 destination for the LPR syslog facility. 21 22 IMPORTANT : please don't send log files to the mailing list 23 unless they are very small of unless someone asked for this. 21 24 22 25 * How can I limit my users to N pages per day (month/year) ? … … 47 50 use the --printer command line argument as well. See 48 51 edpykota's documentation for details. 52 53 Another way to do this when you limit your users by balance, is 54 to set an overcharging factor of zero for every user you want to 55 print with no limitation : 56 57 $ edpykota --add --limitby balance --overcharge 0 user1 user2 ... 49 58 50 59 * Nothing prints when my printer is in PowerSave mode, what -
pykota/trunk/initscripts/ldap/pykota.schema
r2028 r2054 187 187 SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) 188 188 189 # pykota UserCoefficient190 attributetype ( 1.3.6.1.4.1.16868.1.1.27 NAME 'pykota UserCoefficient'191 DESC ' Coefficientfor a particular user, float'189 # pykotaOverCharge 190 attributetype ( 1.3.6.1.4.1.16868.1.1.27 NAME 'pykotaOverCharge' 191 DESC 'OverCharging factor for a particular user, float' 192 192 EQUALITY caseIgnoreIA5Match 193 193 SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE ) … … 270 270 objectclass ( 1.3.6.1.4.1.16868.1.2.7 NAME 'pykotaAccountBalance' SUP top AUXILIARY 271 271 DESC 'PyKota User account balance' 272 MAY ( pykotaUserName $ pykotaBalance $ pykotaLifeTimePaid $ pykota UserCoefficient$ pykotaPayments ) )272 MAY ( pykotaUserName $ pykotaBalance $ pykotaLifeTimePaid $ pykotaOverCharge $ pykotaPayments ) ) 273 273 274 274 # pykotaLastJob -
pykota/trunk/initscripts/postgresql/pykota-postgresql.sql
r2037 r2054 20 20 -- 21 21 -- $Log$ 22 -- Revision 1.16 2005/02/13 22:02:29 jalet 23 -- Big database structure changes. Upgrade script is now included as well as 24 -- the new LDAP schema. 25 -- Introduction of the -o | --overcharge command line option to edpykota. 26 -- The output of repykota is more complete, but doesn't fit in 80 columns anymore. 27 -- Introduction of the new 'maxdenybanners' directive. 28 -- 22 29 -- Revision 1.15 2005/01/23 10:58:22 jalet 23 30 -- Added a few indexes for the database … … 106 113 lifetimepaid FLOAT DEFAULT 0.0, 107 114 limitby TEXT DEFAULT 'quota', 108 coefficientFLOAT NOT NULL DEFAULT 1.0);115 overcharge FLOAT NOT NULL DEFAULT 1.0); 109 116 110 117 -- … … 135 142 hardlimit INT4, 136 143 datelimit TIMESTAMP, 137 warn ed INT4 DEFAULT 0); -- not a boolean, will help stats144 warncount INT4 DEFAULT 0); 138 145 CREATE INDEX userpquota_u_id_ix ON userpquota (userid); 139 146 CREATE INDEX userpquota_p_id_ix ON userpquota (printerid); … … 176 183 hardlimit INT4, 177 184 datelimit TIMESTAMP); 185 CREATE INDEX grouppquota_g_id_ix ON grouppquota (groupid); 186 CREATE INDEX grouppquota_p_id_ix ON grouppquota (printerid); 178 187 CREATE UNIQUE INDEX grouppquota_up_id_ix ON grouppquota (groupid, printerid); 179 188 … … 206 215 printerid INTEGER NOT NULL REFERENCES printers(id), 207 216 label TEXT NOT NULL, 208 coefficient FLOAT NOT NULLDEFAULT 1.0,217 coefficient FLOAT DEFAULT 1.0, 209 218 CONSTRAINT coeffconstraint UNIQUE (printerid, label)); 210 219 … … 212 221 -- Set some ACLs 213 222 -- 214 REVOKE ALL ON users, groups, printers, userpquota, grouppquota, groupsmembers, printergroupsmembers, jobhistory, payments FROM public;215 REVOKE ALL ON users_id_seq, groups_id_seq, printers_id_seq, userpquota_id_seq, grouppquota_id_seq, jobhistory_id_seq, payments_id_seq FROM public;223 REVOKE ALL ON users, groups, printers, userpquota, grouppquota, groupsmembers, printergroupsmembers, jobhistory, payments, coefficients FROM public; 224 REVOKE ALL ON users_id_seq, groups_id_seq, printers_id_seq, userpquota_id_seq, grouppquota_id_seq, jobhistory_id_seq, payments_id_seq, coefficients_id_seq FROM public; 216 225 217 226 GRANT SELECT, INSERT, UPDATE, DELETE, REFERENCES ON users, groups, printers, userpquota, grouppquota, groupsmembers, printergroupsmembers, jobhistory, payments, coefficients TO pykotaadmin; -
pykota/trunk/initscripts/postgresql/README.postgresql
r2028 r2054 59 59 version of PyKota. 60 60 61 * An SQL script to upgrade a 1.20 PyKota Storage DataBase to 62 1.21 is included. Launch it this way on the Quota Storage Server : 63 64 $ psql -U postgres pykota 65 pykota=# \i upgrade-to-1.21.sql 66 pykota=# \q 67 $ 68 69 This script adds many fields to existing tables, and also adds 70 some tables in indexes. 71 61 72 * An SQL script to upgrade a 1.18 PyKota Storage DataBase to 62 73 1.19 is included. Launch it this way on the Quota Storage Server : -
pykota/trunk/NEWS
r2044 r2054 22 22 PyKota NEWS : 23 23 24 - 1.21alpha24 : 25 26 - Big database structure changes. An upgrade script 27 is now included for PostgreSQL. LDAP users may just 28 want to copy the new schema in place. 29 30 - edpykota now recognizes the -o | --overcharge command line 31 option to set an overcharging or undercharging factor 32 on each print job's cost for a particular user. 33 34 - repykota's output format has changed an is not limited to 35 80 characters wide anymore. People who used to parse 36 repykota's output in their own tools are strongly advised 37 to parse dumpykota's output instead. 38 39 - Introduction of the new 'maxdenybanners' configuration directive 40 to allow up to N (the directive's value) deny banners to be 41 printed even if the print account is forbidden to print. 42 43 - Better detection of the number of copies in the PostScript parser. 44 24 45 - 1.21alpha23 : 25 46 -
pykota/trunk/po/fr_FR/pykota.po
r2028 r2054 1120 1120 msgid "Invalid modifier [%s] for --data command line option, see help." 1121 1121 msgstr "" 1122 "Le modifi er [%s] pour l'option de ligne de commande --data est invalide, "1122 "Le modificateur [%s] pour l'option de ligne de commande --data est invalide, " 1123 1123 "voir l'aide." 1124 1124 … … 1126 1126 msgid "Invalid modifier [%s] for --format command line option, see help." 1127 1127 msgstr "" 1128 "Le modifi er [%s] pour l'option de ligne de commande --format est invalide,"1129 " voir l'aide."1128 "Le modificateur [%s] pour l'option de ligne de commande --format est " 1129 "invalide, voir l'aide." 1130 1130 1131 1131 msgid "XML output is disabled because the jaxml module is not available." -
pykota/trunk/po/zh_TW/pykota.po
r2043 r2054 28 28 "Project-Id-Version: PyKota v1.20\n" 29 29 "Report-Msgid-Bugs-To: alet@librelogiciel.com\n" 30 "POT-Creation-Date: 200 5-01-25 09:03+0800\n"30 "POT-Creation-Date: 2004-11-25 10:16+0100\n" 31 31 "PO-Revision-Date: 2005-01-25 09:03+0800\n" 32 32 "Last-Translator: Tsang Yu Pong, Teddy, Wing Kwong College in Hong Kong," … … 39 39 #, python-format 40 40 msgid "" 41 "pkbanner v%s (c) 2003, 2004, 2005 C@LL - Conseil Internet & Logiciels Libres\n" 41 "pkbanner v%s (c) 2003, 2004, 2005 C@LL - Conseil Internet & Logiciels " 42 "Libres\n" 42 43 "\n" 43 44 "Generates banners.\n" … … 292 293 #, python-format 293 294 msgid "" 294 "pkprinters v%s (c) 2003, 2004, 2005 C@LL - Conseil Internet & Logiciels Libres\n" 295 "pkprinters v%s (c) 2003, 2004, 2005 C@LL - Conseil Internet & Logiciels " 296 "Libres\n" 295 297 "A Printers Manager for PyKota.\n" 296 298 "\n" … … 360 362 " $ pkprinters --delete \"*\"\n" 361 363 " \n" 362 " This will completely delete all printers and associated quota "364 " This will completely delete all printers and associated quota " 363 365 "information,\n" 364 366 " as well as their job history. USE WITH CARE !\n" … … 589 591 #, python-format 590 592 msgid "" 591 "autopykota v%s (c) 2003, 2004, 2005 C@LL - Conseil Internet & Logiciels Libres\n" 593 "autopykota v%s (c) 2003, 2004, 2005 C@LL - Conseil Internet & Logiciels " 594 "Libres\n" 592 595 "A tool to automate user account creation and initial balance setting.\n" 593 596 "\n" … … 664 667 #, python-format 665 668 msgid "" 666 "dumpykota v%s (c) 2003, 2004, 2005 C@LL - Conseil Internet & Logiciels Libres\n" 669 "dumpykota v%s (c) 2003, 2004, 2005 C@LL - Conseil Internet & Logiciels " 670 "Libres\n" 667 671 "\n" 668 672 "Dumps PyKota database's content.\n" … … 757 761 #, python-format 758 762 msgid "" 759 "edpykota v%s (c) 2003, 2004, 2005 C@LL - Conseil Internet & Logiciels Libres\n" 763 "edpykota v%s (c) 2003, 2004, 2005 C@LL - Conseil Internet & Logiciels " 764 "Libres\n" 760 765 "A Print Quota editor for PyKota.\n" 761 766 "\n" … … 1014 1019 #, python-format 1015 1020 msgid "" 1016 "repykota v%s (c) 2003, 2004, 2005 C@LL - Conseil Internet & Logiciels Libres\n" 1021 "repykota v%s (c) 2003, 2004, 2005 C@LL - Conseil Internet & Logiciels " 1022 "Libres\n" 1017 1023 "\n" 1018 1024 "Generates print quota reports.\n" … … 1078 1084 #, python-format 1079 1085 msgid "" 1080 "warnpykota v%s (c) 2003, 2004, 2005 C@LL - Conseil Internet & Logiciels Libres\n" 1086 "warnpykota v%s (c) 2003, 2004, 2005 C@LL - Conseil Internet & Logiciels " 1087 "Libres\n" 1081 1088 "\n" 1082 1089 "Sends mail to users over print quota.\n" … … 1255 1262 "paid" 1256 1263 msgstr "" 1257 "群組 已列印 警告限制 有效限制 結餘 寬限日期 付款總計 " 1258 "已繳付" 1259 1264 "群組 已列印 警告限制 有效限制 結餘 寬限日期 付款總" 1265 "計 已繳付" 1260 1266 1261 1267 msgid "" … … 1263 1269 "paid" 1264 1270 msgstr "" 1265 "群組 已列印 警告限制 有效限制 結餘 寬限日期 付款總 計"1266 " 已繳付"1271 "群組 已列印 警告限制 有效限制 結餘 寬限日期 付款總" 1272 "計 已繳付" 1267 1273 1268 1274 msgid "unknown" … … 1314 1320 "Unable to find user %s's account balance, applying default policy (%s) for " 1315 1321 "printer %s" 1316 msgstr "" 1317 "未能尋找使用者 %s 的帳目結算,因此採用預設的政策(%s)於" 1318 "列印機 %s" 1322 msgstr "未能尋找使用者 %s 的帳目結算,因此採用預設的政策(%s)於列印機 %s" 1319 1323 1320 1324 #, python-format … … 1336 1340 msgstr "使用者 %s 的列印配額於列印機 %s 經已超出配額" 1337 1341 1338 #, python1339 1340 1342 #, python-format 1341 1343 msgid "Print Quota low for user %s on printer %s" … … 1345 1347 msgstr "列印配額經已很低" 1346 1348 1347 1348 1349 #, python-format 1349 1350 msgid "Printing system %s, args=%s" … … 1374 1375 "s) for printer %s" 1375 1376 msgstr "" 1376 "列印機 %s 在PyKota系統內沒有登記,因此這台列印機" 1377 "套用external policy (%s) " 1377 "列印機 %s 在PyKota系統內沒有登記,因此這台列印機套用external policy (%s) " 1378 1378 1379 1379 #, python-format … … 1382 1382 "for printer %s" 1383 1383 msgstr "" 1384 "使用者 %s 在PyKota內沒有登記,因此這個使用者將會套用external policy(%s) "1385 " 於列印機 %s "1384 "使用者 %s 在PyKota內沒有登記,因此這個使用者將會套用external policy(%s) 於列" 1385 "印機 %s " 1386 1386 1387 1387 #, python-format … … 1389 1389 "User %s doesn't have quota on printer %s in the PyKota system, applying " 1390 1390 "external policy (%s) for printer %s" 1391 msgstr "" 1392 "使用者沒有列印配額於列印機 %s ,套用對外政策 (%s)" 1393 " 於列印機 %s" 1391 msgstr "使用者沒有列印配額於列印機 %s ,套用對外政策 (%s) 於列印機 %s" 1394 1392 1395 1393 #, python-format … … 1397 1395 "External policy %s for printer %s produced an error. Job rejected. Please " 1398 1396 "check PyKota's configuration files." 1399 msgstr "" 1400 "對外政策 %s 於列印機 %s 產生錯誤,列印工作被拒,請撿查PyKota的設定檔案" 1397 msgstr "對外政策 %s 於列印機 %s 產生錯誤,列印工作被拒,請撿查PyKota的設定檔案" 1401 1398 1402 1399 #, python-format 1403 1400 msgid "" 1404 1401 "Printer %s not registered in the PyKota system, applying default policy (%s)" 1405 msgstr "" 1406 "列印機 %s 沒有於PyKota系統內登記,套用預設的政策 (%s)" 1402 msgstr "列印機 %s 沒有於PyKota系統內登記,套用預設的政策 (%s)" 1407 1403 1408 1404 #, python-format … … 1410 1406 "User %s not registered in the PyKota system, applying default policy (%s) " 1411 1407 "for printer %s" 1412 msgstr "" 1413 "使用者 %s 沒有於PyKota系統內登記,套用預設的政策 (%s)" 1414 "於列印機 %s" 1408 msgstr "使用者 %s 沒有於PyKota系統內登記,套用預設的政策 (%s)於列印機 %s" 1415 1409 1416 1410 #, python-format … … 1418 1412 "User %s doesn't have quota on printer %s in the PyKota system, applying " 1419 1413 "default policy (%s)" 1420 msgstr "" 1421 "使用者 %s 沒有列印配額於列印機 %s,套用預設的政策 (%s)" 1414 msgstr "使用者 %s 沒有列印配額於列印機 %s,套用預設的政策 (%s)" 1422 1415 1423 1416 #, python-format 1424 1417 msgid "" 1425 1418 "Printer %s still not registered in the PyKota system, job will be rejected" 1426 msgstr "" 1427 "列印機 %s 依然沒有於PyKota系統內登記,列印工作要求被拒" 1419 msgstr "列印機 %s 依然沒有於PyKota系統內登記,列印工作要求被拒" 1428 1420 1429 1421 #, python-format … … 1431 1423 "User %s still not registered in the PyKota system, job will be rejected on " 1432 1424 "printer %s" 1433 msgstr "" 1434 "使用者 %s 依然沒有於PyKota系統內登記,列印工作要求被拒於" 1435 "列印機 %s" 1425 msgstr "使用者 %s 依然沒有於PyKota系統內登記,列印工作要求被拒於列印機 %s" 1436 1426 1437 1427 #, python-format … … 1439 1429 "User %s still doesn't have quota on printer %s in the PyKota system, job " 1440 1430 "will be rejected" 1441 msgstr "" 1442 "使用者 %s 依然沒有列印配額於列印機 %s 在PyKota系統,列印工作被拒" 1431 msgstr "使用者 %s 依然沒有列印配額於列印機 %s 在PyKota系統,列印工作被拒" 1443 1432 1444 1433 #, python-format … … 1482 1471 "Couldn't retrieve printer %s's internal page counter either before or after " 1483 1472 "printing." 1484 msgstr "" 1485 "不能恢復列印機 %s 的內存頁面計算器不論在列印的之前或之後" 1473 msgstr "不能恢復列印機 %s 的內存頁面計算器不論在列印的之前或之後" 1486 1474 1487 1475 #, python-format … … 1501 1489 "download it from http://pysnmp.sourceforge.net" 1502 1490 msgstr "" 1503 "要求內存的SNMP計算器,但找不到Python-SNMP "1504 " 請到http://pysnmp.sourceforge.net下載"1491 "要求內存的SNMP計算器,但找不到Python-SNMP請到http://pysnmp.sourceforge.net下" 1492 "載" 1505 1493 1506 1494 #, python-format … … 1532 1520 "SNMP querying stage interrupted. Using latest value seen for internal page " 1533 1521 "counter (%s) on printer %s." 1534 msgstr "" 1535 "SNMP查詢被中斷,使用最更新的數值來計算頁數" 1536 "計算器 (%s) 在列印機 %s 上" 1522 msgstr "SNMP查詢被中斷,使用最更新的數值來計算頁數計算器 (%s) 在列印機 %s 上" 1537 1523 1538 1524 #, python-format … … 1540 1526 "PJL querying stage interrupted. Using latest value seen for internal page " 1541 1527 "counter (%s) on printer %s." 1542 msgstr "" 1543 "PJL查詢被中斷,使用最更新的數值來計算頁數" 1544 "計算器 (%s) 在列印機 %s 上" 1528 msgstr "PJL查詢被中斷,使用最更新的數值來計算頁數計算器 (%s) 在列印機 %s 上" 1545 1529 1546 1530 #, python-format … … 1567 1551 "Search base %s doesn't seem to exist. Probable misconfiguration. Please " 1568 1552 "double check /etc/pykota/pykota.conf : %s" 1569 msgstr "" 1570 "%s 不存在,很可能是錯誤設定所致" 1571 "請撿查 /etc/pykota/pykota.conf : %s" 1553 msgstr "%s 不存在,很可能是錯誤設定所致請撿查 /etc/pykota/pykota.conf : %s" 1572 1554 1573 1555 #, python-format … … 1591 1573 "No pykotaAccountBalance object found for user %s. Did you create LDAP " 1592 1574 "entries manually ?" 1593 msgstr "未能為使用者 %s 尋找pkotaAccountBalance object,請問你是否已手動建立LDAP 紀錄? " 1575 msgstr "" 1576 "未能為使用者 %s 尋找pkotaAccountBalance object,請問你是否已手動建立LDAP 紀" 1577 "錄? " 1594 1578 1595 1579 #, python-format … … 1597 1581 "Unable to find an existing objectClass %s entry with %s=%s to attach " 1598 1582 "pykotaAccount objectClass" 1599 msgstr " 未能尋找現存的objectclass %s 紀錄帶有 %s=%s"1600 " 連繫到pykotaAccount objectClass "1583 msgstr "" 1584 "未能尋找現存的objectclass %s 紀錄帶有 %s=%s 連繫到pykotaAccount objectClass " 1601 1585 1602 1586 #, python-format -
pykota/trunk/pykota/config.py
r1968 r2054 22 22 # 23 23 # $Log$ 24 # Revision 1.59 2005/02/13 22:02:29 jalet 25 # Big database structure changes. Upgrade script is now included as well as 26 # the new LDAP schema. 27 # Introduction of the -o | --overcharge command line option to edpykota. 28 # The output of repykota is more complete, but doesn't fit in 80 columns anymore. 29 # Introduction of the new 'maxdenybanners' directive. 30 # 24 31 # Revision 1.58 2004/12/02 22:01:58 jalet 25 32 # TLS is now supported with the LDAP backend … … 507 514 return (mailto, args) 508 515 516 def getMaxDenyBanners(self, printername) : 517 """Returns the maximum number of deny banners to be printed for a particular user on a particular printer.""" 518 try : 519 maxdb = self.getPrinterOption(printername, "maxdenybanners") 520 except PyKotaConfigError : 521 return 0 # default value is to forbid printing a deny banner. 522 try : 523 value = int(maxdb.strip()) 524 if value < 0 : 525 raise ValueError 526 except (TypeError, ValueError) : 527 raise PyKotaConfigError, _("Invalid maximal deny banners counter %s") % maxdb 528 else : 529 return value 530 509 531 def getGraceDelay(self, printername) : 510 532 """Returns the grace delay in days.""" -
pykota/trunk/pykota/reporter.py
r1692 r2054 22 22 # 23 23 # $Log$ 24 # Revision 1.11 2005/02/13 22:02:29 jalet 25 # Big database structure changes. Upgrade script is now included as well as 26 # the new LDAP schema. 27 # Introduction of the -o | --overcharge command line option to edpykota. 28 # The output of repykota is more complete, but doesn't fit in 80 columns anymore. 29 # Introduction of the new 'maxdenybanners' directive. 30 # 24 31 # Revision 1.10 2004/09/02 10:09:30 jalet 25 32 # Fixed bug in LDAP user deletion code which didn't correctly delete the user's … … 87 94 def getReportHeader(self) : 88 95 if self.isgroup : 89 return _("Group used soft hard balance grace total paid")96 return _("Group overcharge used soft hard balance grace total paid warn") 90 97 else : 91 return _("User used soft hard balance grace total paid")98 return _("User overcharge used soft hard balance grace total paid warn") 92 99 93 100 def getPrinterRealPageCounter(self, printer) : … … 109 116 balance = float(entry.AccountBalance or 0.0) 110 117 lifetimepaid = float(entry.LifeTimePaid or 0.0) 118 if not hasattr(entry, "OverCharge") : 119 overcharge = _("N/A") # Not available for groups 120 else : 121 overcharge = float(entry.OverCharge or 0.0) 122 if not hasattr(quota, "WarnCount") : 123 warncount = _("N/A") # Not available for groups 124 else : 125 warncount = int(quota.WarnCount or 0) 111 126 112 127 #balance … … 199 214 strbalance = ("%5.2f" % balance)[:10] 200 215 strlifetimepaid = ("%6.2f" % lifetimepaid)[:10] 201 return (lifepagecounter, lifetimepaid, entry.Name, reached, pagecounter, str(quota.SoftLimit), str(quota.HardLimit), strbalance, str(datelimit)[:10], lifepagecounter, strlifetimepaid) 216 strovercharge = ("%5s" % overcharge)[:5] 217 strwarncount = ("%4s" % warncount)[:4] 218 return (lifepagecounter, lifetimepaid, entry.Name, reached, \ 219 pagecounter, str(quota.SoftLimit), str(quota.HardLimit), \ 220 strbalance, str(datelimit)[:10], lifepagecounter, \ 221 strlifetimepaid, strovercharge, strwarncount) 202 222 203 223 def openReporter(tool, reporttype, printers, ugnames, isgroup) : -
pykota/trunk/pykota/reporters/html.py
r1278 r2054 22 22 # 23 23 # $Log$ 24 # Revision 1.9 2005/02/13 22:02:29 jalet 25 # Big database structure changes. Upgrade script is now included as well as 26 # the new LDAP schema. 27 # Introduction of the -o | --overcharge command line option to edpykota. 28 # The output of repykota is more complete, but doesn't fit in 80 columns anymore. 29 # Introduction of the new 'maxdenybanners' directive. 30 # 24 31 # Revision 1.8 2004/01/12 15:28:45 jalet 25 32 # Now can output the user's history on several printers at the same time. … … 81 88 else : 82 89 oddevenclass = "even" 83 (pages, money, name, reached, pagecounter, soft, hard, balance, datelimit, lifepagecounter, lifetimepaid ) = self.getQuota(entry, entrypquota)90 (pages, money, name, reached, pagecounter, soft, hard, balance, datelimit, lifepagecounter, lifetimepaid, overcharge, warncount) = self.getQuota(entry, entrypquota) 84 91 if datelimit : 85 92 if datelimit == "DENY" : … … 89 96 if (not self.tool.config.getDisableHistory()) and (not self.isgroup) : 90 97 name = '<a href="%s?username=%s&printername=%s&history=1">%s</a>' % (os.environ.get("SCRIPT_NAME", ""), name, printer.Name, name) 91 self.report.append('<tr class="%s">%s</tr>' % (oddevenclass, "".join(["<td>%s</td>" % h for h in (name, reached, pagecounter, soft, hard, balance, datelimit or " ", lifepagecounter, lifetimepaid)])))98 self.report.append('<tr class="%s">%s</tr>' % (oddevenclass, "".join(["<td>%s</td>" % h for h in (name, reached, overcharge, pagecounter, soft, hard, balance, datelimit or " ", lifepagecounter, lifetimepaid, warncount)]))) 92 99 total += pages 93 100 totalmoney += money … … 95 102 if total or totalmoney : 96 103 (tpage, tmoney) = self.getTotals(total, totalmoney) 97 self.report.append('<tr class="totals"><td colspan=" 7"> </td><td align="right">%s</td><td align="right">%s</td></tr>' % (tpage, tmoney))98 self.report.append('<tr class="realpagecounter"><td colspan=" 7"> </td><td align="right">%s</td></tr>' % self.getPrinterRealPageCounter(printer))104 self.report.append('<tr class="totals"><td colspan="8"> </td><td align="right">%s</td><td align="right">%s</td><td> </td></tr>' % (tpage, tmoney)) 105 self.report.append('<tr class="realpagecounter"><td colspan="8"> </td><td align="right">%s</td><td> </td></tr>' % self.getPrinterRealPageCounter(printer)) 99 106 self.report.append('</table>') 100 107 if self.isgroup : -
pykota/trunk/pykota/reporters/text.py
r1257 r2054 22 22 # 23 23 # $Log$ 24 # Revision 1.10 2005/02/13 22:02:29 jalet 25 # Big database structure changes. Upgrade script is now included as well as 26 # the new LDAP schema. 27 # Introduction of the -o | --overcharge command line option to edpykota. 28 # The output of repykota is more complete, but doesn't fit in 80 columns anymore. 29 # Introduction of the new 'maxdenybanners' directive. 30 # 24 31 # Revision 1.9 2004/01/08 14:10:33 jalet 25 32 # Copyright year changed. … … 78 85 self.report.append('-' * len(header)) 79 86 for (entry, entrypquota) in getattr(self.tool.storage, "getPrinter%ssAndQuotas" % prefix)(printer, self.ugnames) : 80 (pages, money, name, reached, pagecounter, soft, hard, balance, datelimit, lifepagecounter, lifetimepaid ) = self.getQuota(entry, entrypquota)81 self.report.append("%- 9.9s %s %7i %7s %7s %10s %-10.10s %8i %10s" % (name, reached, pagecounter, soft, hard, balance, datelimit, lifepagecounter, lifetimepaid))87 (pages, money, name, reached, pagecounter, soft, hard, balance, datelimit, lifepagecounter, lifetimepaid, overcharge, warncount) = self.getQuota(entry, entrypquota) 88 self.report.append("%-15.15s %s %5s %7i %7s %7s %10s %-10.10s %8i %10s %4s" % (name, reached, overcharge, pagecounter, soft, hard, balance, datelimit, lifepagecounter, lifetimepaid, warncount)) 82 89 total += pages 83 90 totalmoney += money … … 85 92 if total or totalmoney : 86 93 (tpage, tmoney) = self.getTotals(total, totalmoney) 87 self.report.append((" " * 50) + tpage + tmoney)88 self.report.append((" " * 51) + self.getPrinterRealPageCounter(printer))94 self.report.append((" " * 62) + tpage + tmoney) 95 self.report.append((" " * 63) + self.getPrinterRealPageCounter(printer)) 89 96 self.report.append("") 90 97 if self.isgroup : -
pykota/trunk/pykota/storage.py
r2030 r2054 22 22 # 23 23 # $Log$ 24 # Revision 1.68 2005/02/13 22:02:29 jalet 25 # Big database structure changes. Upgrade script is now included as well as 26 # the new LDAP schema. 27 # Introduction of the -o | --overcharge command line option to edpykota. 28 # The output of repykota is more complete, but doesn't fit in 80 columns anymore. 29 # Introduction of the new 'maxdenybanners' directive. 30 # 24 31 # Revision 1.67 2005/01/18 19:47:50 jalet 25 32 # Big bug fix wrt the datelimit attribute … … 276 283 self.LifeTimePaid = None 277 284 self.Email = None 285 self.OverCharge = 1.0 278 286 self.Payments = [] # TODO : maybe handle this smartly for SQL, for now just don't retrieve them 279 287 … … 308 316 self.LimitBy = limitby 309 317 318 def setOverChargeFactor(self, factor) : 319 """Sets the user's overcharging coefficient.""" 320 self.parent.writeUserOverCharge(self, factor) 321 self.OverCharge = factor 322 310 323 def delete(self) : 311 324 """Deletes an user from the Quota Storage.""" … … 357 370 self.PricePerJob = None 358 371 self.Description = None 372 self.Coefficients = None 359 373 360 374 def __getattr__(self, name) : … … 424 438 self.HardLimit = None 425 439 self.DateLimit = None 440 self.WarnCount = None 426 441 427 442 def __getattr__(self, name) : … … 445 460 self.HardLimit = hardlimit 446 461 self.DateLimit = None 462 self.WarnCount = 0 447 463 448 464 def setUsage(self, used) : … … 454 470 self.parent.increaseUserPQuotaPagesCounters(self, vused) 455 471 self.parent.writeUserPQuotaDateLimit(self, None) 472 self.parent.writeUserPQuotaWarnCount(self, 0) 456 473 except PyKotaStorageError, msg : 457 474 self.parent.rollbackTransaction() … … 465 482 self.PageCounter = self.LifePageCounter = vused 466 483 self.DateLimit = None 484 self.WarnCount = 0 467 485 486 def warn(self) : 487 """Increases the warn counter for this user quota.""" 488 self.parent.increaseUserPQuotaWarnCount(self) 489 self.WarnCount = (self.WarnCount or 0) + 1 490 468 491 def reset(self) : 469 492 """Resets page counter to 0.""" … … 482 505 totalprice = 0.0 483 506 if jobsize : 484 for upq in [ self ] + self.ParentPrintersUserPQuota : 485 price = (float(upq.Printer.PricePerPage or 0.0) * jobsize) + float(upq.Printer.PricePerJob or 0.0) 486 totalprice += price 487 return totalprice 507 if self.User.OverCharge != 0.0 : # optimization, but TODO : beware of rounding errors 508 for upq in [ self ] + self.ParentPrintersUserPQuota : 509 price = (float(upq.Printer.PricePerPage or 0.0) * jobsize) + float(upq.Printer.PricePerJob or 0.0) 510 totalprice += price 511 if self.User.OverCharge != 1.0 : # TODO : beware of rounding errors 512 overcharged = totalprice * self.User.OverCharge 513 self.parent.tool.printInfo("Overcharging %s by a factor of %s ===> User %s will be charged for %s units." % (totalprice, self.User.OverCharge, self.User.Name, overcharged)) 514 return overcharged 515 else : 516 return totalprice 488 517 489 518 def increasePagesUsage(self, jobsize) : … … 589 618 self.JobOptions = None 590 619 self.JobHostName = None 620 self.JobMD5Sum = None 621 self.JobPages = None 622 self.JobBillingCode = None 591 623 592 624 def __getattr__(self, name) : -
pykota/trunk/pykota/storages/ldapstorage.py
r2042 r2054 22 22 # 23 23 # $Log$ 24 # Revision 1.100 2005/02/13 22:02:29 jalet 25 # Big database structure changes. Upgrade script is now included as well as 26 # the new LDAP schema. 27 # Introduction of the -o | --overcharge command line option to edpykota. 28 # The output of repykota is more complete, but doesn't fit in 80 columns anymore. 29 # Introduction of the new 'maxdenybanners' directive. 30 # 24 31 # Revision 1.99 2005/01/24 17:44:17 jalet 25 32 # Same fix for group print quota entries wrt LDAP performance … … 647 654 """Extracts user information given its name.""" 648 655 user = StorageUser(self, username) 649 result = self.doSearch("(&(objectClass=pykotaAccount)(|(pykotaUserName=%s)(%s=%s)))" % (username, self.info["userrdn"], username), ["pykotaUserName", "pykotaLimitBy", self.info["usermail"] ], base=self.info["userbase"])656 result = self.doSearch("(&(objectClass=pykotaAccount)(|(pykotaUserName=%s)(%s=%s)))" % (username, self.info["userrdn"], username), ["pykotaUserName", "pykotaLimitBy", self.info["usermail"], "pykotaOverCharge"], base=self.info["userbase"]) 650 657 if result : 651 658 fields = result[0][1] 652 659 user.ident = result[0][0] 653 660 user.Name = fields.get("pykotaUserName", [username])[0] 654 user.Email = fields.get(self.info["usermail"]) 655 if user.Email is not None : 656 user.Email = user.Email[0] 657 user.LimitBy = fields.get("pykotaLimitBy") 658 if user.LimitBy is not None : 659 user.LimitBy = user.LimitBy[0] 660 else : 661 user.LimitBy = "quota" 661 user.Email = fields.get(self.info["usermail"], [None])[0] 662 user.LimitBy = fields.get("pykotaLimitBy", ["quota"])[0] 663 user.OverCharge = float(fields.get("pykotaOverCharge", [1.0])[0]) 662 664 result = self.doSearch("(&(objectClass=pykotaAccountBalance)(|(pykotaUserName=%s)(%s=%s)))" % (username, self.info["balancerdn"], username), ["pykotaBalance", "pykotaLifeTimePaid", "pykotaPayments"], base=self.info["balancebase"]) 663 665 if not result : … … 695 697 group.ident = result[0][0] 696 698 group.Name = fields.get("pykotaGroupName", [groupname])[0] 697 group.LimitBy = fields.get("pykotaLimitBy") 698 if group.LimitBy is not None : 699 group.LimitBy = group.LimitBy[0] 700 else : 701 group.LimitBy = "quota" 699 group.LimitBy = fields.get("pykotaLimitBy", ["quota"])[0] 702 700 group.AccountBalance = 0.0 703 701 group.LifeTimePaid = 0.0 … … 717 715 printer.ident = result[0][0] 718 716 printer.Name = fields.get("pykotaPrinterName", [printername])[0] 719 printer.PricePerJob = float(fields.get("pykotaPricePerJob", [0.0])[0] or 0.0)720 printer.PricePerPage = float(fields.get("pykotaPricePerPage", [0.0])[0] or 0.0)717 printer.PricePerJob = float(fields.get("pykotaPricePerJob", [0.0])[0]) 718 printer.PricePerPage = float(fields.get("pykotaPricePerPage", [0.0])[0]) 721 719 printer.uniqueMember = fields.get("uniqueMember", []) 722 720 printer.Description = self.databaseToUserCharset(fields.get("description", [""])[0]) … … 732 730 else : 733 731 base = self.info["userquotabase"] 734 result = self.doSearch("(&(objectClass=pykotaUserPQuota)(pykotaUserName=%s)(pykotaPrinterName=%s))" % (user.Name, printer.Name), ["pykotaPageCounter", "pykotaLifePageCounter", "pykotaSoftLimit", "pykotaHardLimit", "pykotaDateLimit" ], base=base)732 result = self.doSearch("(&(objectClass=pykotaUserPQuota)(pykotaUserName=%s)(pykotaPrinterName=%s))" % (user.Name, printer.Name), ["pykotaPageCounter", "pykotaLifePageCounter", "pykotaSoftLimit", "pykotaHardLimit", "pykotaDateLimit", "pykotaWarnCount"], base=base) 735 733 if result : 736 734 fields = result[0][1] 737 735 userpquota.ident = result[0][0] 738 userpquota.PageCounter = int(fields.get("pykotaPageCounter", [0])[0] or 0) 739 userpquota.LifePageCounter = int(fields.get("pykotaLifePageCounter", [0])[0] or 0) 736 userpquota.PageCounter = int(fields.get("pykotaPageCounter", [0])[0]) 737 userpquota.LifePageCounter = int(fields.get("pykotaLifePageCounter", [0])[0]) 738 userpquota.WarnCount = int(fields.get("pykotaWarnCount", [0])[0]) 740 739 userpquota.SoftLimit = fields.get("pykotaSoftLimit") 741 740 if userpquota.SoftLimit is not None : … … 815 814 result = None 816 815 try : 817 result = self.doSearch("objectClass=pykotaJob", ["pykotaJobSizeBytes", "pykotaHostName", "pykotaUserName", "pykotaJobId", "pykotaPrinterPageCounter", "pykotaJobSize", "pykotaAction", "pykotaJobPrice", "pykotaFileName", "pykotaTitle", "pykotaCopies", "pykotaOptions", " createTimestamp"], base="cn=%s,%s" % (lastjobident, self.info["jobbase"]), scope=ldap.SCOPE_BASE)816 result = self.doSearch("objectClass=pykotaJob", ["pykotaJobSizeBytes", "pykotaHostName", "pykotaUserName", "pykotaJobId", "pykotaPrinterPageCounter", "pykotaJobSize", "pykotaAction", "pykotaJobPrice", "pykotaFileName", "pykotaTitle", "pykotaCopies", "pykotaOptions", "pykotaBillingCode", "pykotaPages", "pykotaMD5Sum", "createTimestamp"], base="cn=%s,%s" % (lastjobident, self.info["jobbase"]), scope=ldap.SCOPE_BASE) 818 817 except PyKotaStorageError : 819 818 pass # Last job entry exists, but job probably doesn't exist anymore. … … 823 822 lastjob.JobId = fields.get("pykotaJobId")[0] 824 823 lastjob.UserName = fields.get("pykotaUserName")[0] 825 lastjob.PrinterPageCounter = int(fields.get("pykotaPrinterPageCounter", [0])[0] or 0)824 lastjob.PrinterPageCounter = int(fields.get("pykotaPrinterPageCounter", [0])[0]) 826 825 try : 827 826 lastjob.JobSize = int(fields.get("pykotaJobSize", [0])[0]) … … 839 838 lastjob.JobHostName = fields.get("pykotaHostName", [""])[0] 840 839 lastjob.JobSizeBytes = fields.get("pykotaJobSizeBytes", [0L])[0] 840 lastjob.JobBillingCode = fields.get("pykotaMD5Sum", [None])[0] 841 lastjob.JobMD5Sum = fields.get("pykotaMD5Sum", [None])[0] 842 lastjob.JobPages = fields.get("pykotaPages", [""])[0] 841 843 date = fields.get("createTimestamp", ["19700101000000"])[0] 842 844 year = int(date[:4]) … … 924 926 else : 925 927 base = self.info["userquotabase"] 926 result = self.doSearch("(&(objectClass=pykotaUserPQuota)(pykotaPrinterName=%s)(|%s))" % (printer.Name, "".join(["(pykotaUserName=%s)" % uname for uname in names])), ["pykotaUserName", "pykotaPageCounter", "pykotaLifePageCounter", "pykotaSoftLimit", "pykotaHardLimit", "pykotaDateLimit" ], base=base)928 result = self.doSearch("(&(objectClass=pykotaUserPQuota)(pykotaPrinterName=%s)(|%s))" % (printer.Name, "".join(["(pykotaUserName=%s)" % uname for uname in names])), ["pykotaUserName", "pykotaPageCounter", "pykotaLifePageCounter", "pykotaSoftLimit", "pykotaHardLimit", "pykotaDateLimit", "pykotaWarnCount"], base=base) 927 929 if result : 928 930 for (userquotaid, fields) in result : … … 930 932 userpquota = StorageUserPQuota(self, user, printer) 931 933 userpquota.ident = userquotaid 932 userpquota.PageCounter = int(fields.get("pykotaPageCounter", [0])[0] or 0) 933 userpquota.LifePageCounter = int(fields.get("pykotaLifePageCounter", [0])[0] or 0) 934 userpquota.PageCounter = int(fields.get("pykotaPageCounter", [0])[0]) 935 userpquota.LifePageCounter = int(fields.get("pykotaLifePageCounter", [0])[0]) 936 userpquota.WarnCount = int(fields.get("pykotaWarnCount", [0])[0]) 934 937 userpquota.SoftLimit = fields.get("pykotaSoftLimit") 935 938 if userpquota.SoftLimit is not None : … … 990 993 "pykotaUserName" : user.Name, 991 994 "pykotaLimitBy" : (user.LimitBy or "quota"), 995 "pykotaOverCharge" : str(user.OverCharge), 992 996 } 993 997 … … 1048 1052 newfields = { 1049 1053 "pykotaGroupName" : group.Name, 1050 "pykotaLimitB Y" : (group.LimitBy or "quota"),1054 "pykotaLimitBy" : (group.LimitBy or "quota"), 1051 1055 } 1052 1056 mustadd = 1 … … 1102 1106 "pykotaPageCounter" : "0", 1103 1107 "pykotaLifePageCounter" : "0", 1108 "pykotaWarnCount" : "0", 1104 1109 } 1105 1110 if self.info["userquotabase"].lower() == "user" : … … 1141 1146 self.doModify(printer.ident, fields) 1142 1147 1148 def writeUserOverCharge(self, user, factor) : 1149 """Sets the user's overcharging coefficient.""" 1150 fields = { 1151 "pykotaOverCharge" : str(factor), 1152 } 1153 self.doModify(user.ident, fields) 1154 1143 1155 def writeUserLimitBy(self, user, limitby) : 1144 1156 """Sets the user's limiting factor.""" … … 1183 1195 "pykotaLifePageCounter" : str(newlifepagecounter), 1184 1196 "pykotaDateLimit" : None, 1197 "pykotaWarnCount" : "0", 1185 1198 } 1186 1199 return self.doModify(userpquota.ident, fields) … … 1246 1259 "pykotaHostName" : str(clienthost), 1247 1260 "pykotaJobSizeBytes" : str(jobsizebytes), 1261 # TODO : add the 3 missing fields 1248 1262 } 1249 1263 if (not self.disablehistory) or (not printer.LastJob.Exists) : … … 1278 1292 "pykotaHardLimit" : str(hardlimit), 1279 1293 "pykotaDateLimit" : "None", 1294 "pykotaWarnCount" : "0", 1280 1295 } 1281 1296 self.doModify(userpquota.ident, fields) 1297 1298 def writeUserPQuotaWarnCount(self, userpquota, warncount) : 1299 """Sets the warn counter value for a user quota.""" 1300 fields = { 1301 "pykotaWarnCount" : str(warncount or 0), 1302 } 1303 self.doModify(userpquota.ident, fields) 1304 1305 def increaseUserPQuotaWarnCount(self, userpquota) : 1306 """Increases the warn counter value for a user quota.""" 1307 fields = { 1308 "pykotaWarnCount" : { "operator" : "+", "value" : 1, "convert" : int }, 1309 } 1310 return self.doModify(userpquota.ident, fields) 1282 1311 1283 1312 def writeGroupPQuotaLimits(self, grouppquota, softlimit, hardlimit) : -
pykota/trunk/pykota/storages/sql.py
r2030 r2054 22 22 # 23 23 # $Log$ 24 # Revision 1.65 2005/02/13 22:02:29 jalet 25 # Big database structure changes. Upgrade script is now included as well as 26 # the new LDAP schema. 27 # Introduction of the -o | --overcharge command line option to edpykota. 28 # The output of repykota is more complete, but doesn't fit in 80 columns anymore. 29 # Introduction of the new 'maxdenybanners' directive. 30 # 24 31 # Revision 1.64 2005/01/18 19:47:50 jalet 25 32 # Big bug fix wrt the datelimit attribute … … 273 280 user.LifeTimePaid = fields.get("lifetimepaid") 274 281 user.Email = fields.get("email") 282 user.OverCharge = fields.get("overcharge", 1.0) 275 283 user.Exists = 1 276 284 return user … … 317 325 userpquota.HardLimit = fields.get("hardlimit") 318 326 userpquota.DateLimit = fields.get("datelimit") 327 userpquota.WarnCount = fields.get("warncount") 319 328 userpquota.Exists = 1 320 329 return userpquota … … 359 368 lastjob.JobHostName = fields.get("hostname") 360 369 lastjob.JobSizeBytes = fields.get("jobsizebytes") 370 lastjob.JobMD5Sum = fields.get("md5sum") 371 lastjob.JobPages = fields.get("pages") 372 lastjob.JobBillingCode = fields.get("billingcode") 361 373 lastjob.Exists = 1 362 374 return lastjob … … 374 386 user.LifeTimePaid = record.get("lifetimepaid") 375 387 user.Email = record.get("email") 388 user.OverCharge = record.get("overcharge") 376 389 user.Exists = 1 377 390 groupmembers.append(user) … … 423 436 """Returns the list of users who uses a given printer, along with their quotas.""" 424 437 usersandquotas = [] 425 result = self.doSearch("SELECT users.id as uid,username,balance,lifetimepaid,limitby,email, userpquota.id,lifepagecounter,pagecounter,softlimit,hardlimit,datelimit FROM users JOIN userpquota ON users.id=userpquota.userid AND printerid=%s ORDER BY username ASC" % self.doQuote(printer.ident))438 result = self.doSearch("SELECT users.id as uid,username,balance,lifetimepaid,limitby,email,overcharge,userpquota.id,lifepagecounter,pagecounter,softlimit,hardlimit,datelimit,warncount FROM users JOIN userpquota ON users.id=userpquota.userid AND printerid=%s ORDER BY username ASC" % self.doQuote(printer.ident)) 426 439 if result : 427 440 for record in result : … … 433 446 user.LifeTimePaid = record.get("lifetimepaid") 434 447 user.Email = record.get("email") 448 user.OverCharge = record.get("overcharge") 435 449 user.Exists = 1 436 450 userpquota = StorageUserPQuota(self, user, printer) … … 441 455 userpquota.HardLimit = record.get("hardlimit") 442 456 userpquota.DateLimit = record.get("datelimit") 457 userpquota.WarnCount = record.get("warncount") 443 458 userpquota.Exists = 1 444 459 usersandquotas.append((user, userpquota)) … … 466 481 def addUser(self, user) : 467 482 """Adds a user to the quota storage, returns its id.""" 468 self.doModify("INSERT INTO users (username, limitby, balance, lifetimepaid, email ) VALUES (%s, %s, %s, %s, %s)" % (self.doQuote(user.Name), self.doQuote(user.LimitBy or 'quota'), self.doQuote(user.AccountBalance or 0.0), self.doQuote(user.LifeTimePaid or 0.0), self.doQuote(user.Email)))483 self.doModify("INSERT INTO users (username, limitby, balance, lifetimepaid, email, overcharge) VALUES (%s, %s, %s, %s, %s, %s)" % (self.doQuote(user.Name), self.doQuote(user.LimitBy or 'quota'), self.doQuote(user.AccountBalance or 0.0), self.doQuote(user.LifeTimePaid or 0.0), self.doQuote(user.Email), self.doQuote(user.OverCharge))) 469 484 return self.getUser(user.Name) 470 485 … … 503 518 self.doModify("UPDATE printers SET description=%s WHERE id=%s" % (self.doQuote(description), self.doQuote(printer.ident))) 504 519 520 def writeUserOverCharge(self, user, factor) : 521 """Sets the user's overcharging coefficient.""" 522 self.doModify("UPDATE users SET overcharge=%s WHERE id=%s" % (self.doQuote(factor), self.doQuote(user.ident))) 523 505 524 def writeUserLimitBy(self, user, limitby) : 506 525 """Sets the user's limiting factor.""" … … 521 540 def increaseUserPQuotaPagesCounters(self, userpquota, nbpages) : 522 541 """Increase page counters for a user print quota.""" 523 self.doModify("UPDATE userpquota SET pagecounter=pagecounter +%s,lifepagecounter=lifepagecounter+%s WHERE id=%s" % (self.doQuote(nbpages), self.doQuote(nbpages), self.doQuote(userpquota.ident)))542 self.doModify("UPDATE userpquota SET pagecounter=pagecounter + %s,lifepagecounter=lifepagecounter + %s WHERE id=%s" % (self.doQuote(nbpages), self.doQuote(nbpages), self.doQuote(userpquota.ident))) 524 543 525 544 def writeUserPQuotaPagesCounters(self, userpquota, newpagecounter, newlifepagecounter) : 526 545 """Sets the new page counters permanently for a user print quota.""" 527 self.doModify("UPDATE userpquota SET pagecounter=%s, lifepagecounter=%s, datelimit=NULL WHERE id=%s" % (self.doQuote(newpagecounter), self.doQuote(newlifepagecounter), self.doQuote(userpquota.ident)))546 self.doModify("UPDATE userpquota SET pagecounter=%s, lifepagecounter=%s, warncount=0, datelimit=NULL WHERE id=%s" % (self.doQuote(newpagecounter), self.doQuote(newlifepagecounter), self.doQuote(userpquota.ident))) 528 547 529 548 def decreaseUserAccountBalance(self, user, amount) : 530 549 """Decreases user's account balance from an amount.""" 531 self.doModify("UPDATE users SET balance=balance -%s WHERE id=%s" % (self.doQuote(amount), self.doQuote(user.ident)))550 self.doModify("UPDATE users SET balance=balance - %s WHERE id=%s" % (self.doQuote(amount), self.doQuote(user.ident))) 532 551 533 552 def writeUserAccountBalance(self, user, newbalance, newlifetimepaid=None) : … … 565 584 def writeUserPQuotaLimits(self, userpquota, softlimit, hardlimit) : 566 585 """Sets soft and hard limits for a user quota.""" 567 self.doModify("UPDATE userpquota SET softlimit=%s, hardlimit=%s, datelimit=NULL WHERE id=%s" % (self.doQuote(softlimit), self.doQuote(hardlimit), self.doQuote(userpquota.ident))) 586 self.doModify("UPDATE userpquota SET softlimit=%s, hardlimit=%s, warncount=0, datelimit=NULL WHERE id=%s" % (self.doQuote(softlimit), self.doQuote(hardlimit), self.doQuote(userpquota.ident))) 587 588 def writeUserPQuotaWarnCount(self, userpquota, warncount) : 589 """Sets the warn counter value for a user quota.""" 590 self.doModify("UPDATE userpquota SET warncount=%s WHERE id=%s" % (self.doQuote(warncount), self.doQuote(userpquota.ident))) 591 592 def increaseUserPQuotaWarnCount(self, userpquota) : 593 """Increases the warn counter value for a user quota.""" 594 self.doModify("UPDATE userpquota SET warncount=warncount+1 WHERE id=%s" % self.doQuote(userpquota.ident)) 568 595 569 596 def writeGroupPQuotaLimits(self, grouppquota, softlimit, hardlimit) : … … 620 647 job.JobHostName = fields.get("hostname") 621 648 job.JobSizeBytes = fields.get("jobsizebytes") 649 job.JobMD5Sum = fields.get("md5sum") 650 job.JobPages = fields.get("pages") 651 job.JobBillingCode = fields.get("billingcode") 622 652 job.UserName = fields.get("username") 623 653 job.PrinterName = fields.get("printername") -
pykota/trunk/pykota/tool.py
r2008 r2054 22 22 # 23 23 # $Log$ 24 # Revision 1.149 2005/02/13 22:02:29 jalet 25 # Big database structure changes. Upgrade script is now included as well as 26 # the new LDAP schema. 27 # Introduction of the -o | --overcharge command line option to edpykota. 28 # The output of repykota is more complete, but doesn't fit in 80 columns anymore. 29 # Introduction of the new 'maxdenybanners' directive. 30 # 24 31 # Revision 1.148 2005/01/06 23:24:21 jalet 25 32 # Regain priviledge the time to open the job's data file when printing in … … 1012 1019 return action 1013 1020 else : 1014 val = float(user.AccountBalance or 0.0) 1015 enforcement = self.config.getPrinterEnforcement(printer.Name) 1016 if enforcement == "STRICT" : 1017 val -= self.softwareJobPrice # use precomputed size. 1018 if val <= 0.0 : 1019 action = "DENY" 1020 elif val <= self.config.getPoorMan() : 1021 action = "WARN" 1021 if user.OverCharge == 0.0 : 1022 self.printInfo(_("User %s will not be charged for printing.") % user.Name) 1023 action = "ALLOW" 1022 1024 else : 1023 action = "ALLOW" 1024 if (enforcement == "STRICT") and (val == 0.0) : 1025 action = "WARN" # we can still print until account is 0 1025 val = float(user.AccountBalance or 0.0) 1026 enforcement = self.config.getPrinterEnforcement(printer.Name) 1027 if enforcement == "STRICT" : 1028 val -= self.softwareJobPrice # use precomputed size. 1029 if val <= 0.0 : 1030 action = "DENY" 1031 elif val <= self.config.getPoorMan() : 1032 action = "WARN" 1033 else : 1034 action = "ALLOW" 1035 if (enforcement == "STRICT") and (val == 0.0) : 1036 action = "WARN" # we can still print until account is 0 1026 1037 return action 1027 1038 else : … … 1106 1117 if action.startswith("POLICY_") : 1107 1118 action = action[7:] 1119 1108 1120 if action == "DENY" : 1109 1121 adminmessage = _("Print Quota exceeded for user %s on printer %s") % (user.Name, printer.Name) … … 1286 1298 def exportUserInfo(self, userpquota) : 1287 1299 """Exports user information to the environment.""" 1300 os.environ["PYKOTAOVERCHARGE"] = str(userpquota.User.OverCharge) 1288 1301 os.environ["PYKOTALIMITBY"] = str(userpquota.User.LimitBy) 1289 1302 os.environ["PYKOTABALANCE"] = str(userpquota.User.AccountBalance or 0.0) … … 1294 1307 os.environ["PYKOTAHARDLIMIT"] = str(userpquota.HardLimit) 1295 1308 os.environ["PYKOTADATELIMIT"] = str(userpquota.DateLimit) 1309 os.environ["PYKOTAWARNCOUNT"] = str(userpquota.WarnCount) 1296 1310 1297 1311 # not really an user information, but anyway -
pykota/trunk/pykota/version.py
r2044 r2054 22 22 # 23 23 24 __version__ = "1.21alpha2 3_unofficial"24 __version__ = "1.21alpha24_unofficial" 25 25 26 26 __doc__ = """PyKota : a complete Printing Quota Solution for CUPS and LPRng.""" -
pykota/trunk/README
r2051 r2054 250 250 You may learn more about PyKota, if it fits your own organization, 251 251 its internal working, and some potential performance drawbacks and 252 how to avoid them, in a WiKi administered by Ryan Suarez at :252 how to avoid them, in a document created by Ryan Suarez at : 253 253 254 254 http://archive.macosxlabs.org/forum/webcrossing_archive/documentation/Pykota_and_CUPS/Pykota_and_CUPS.html … … 610 610 611 611 which will print quota usage for all users on all printers, 612 along with totals, if you are the root user. If you are612 along with totals, if you are a PyKota Administator. If you are 613 613 a regular user, only your own quota report will be produced. 614 614 … … 631 631 632 632 - Kanakorn Horsiritham developped phpPykotaAdmin which is 633 a web based administrative GUI :633 a web based database independant administrative GUI : 634 634 635 635 http://opensource.psu.ac.th/~kanakorn/mambo/ -
pykota/trunk/TODO
r2028 r2054 36 36 - Better --prototype option in edpykota 37 37 38 - Web enabled pykotme and dumpykota.38 - Web enabled pykotme. 39 39 40 40 - Add an MD5 checksum of the job's datas to the … … 47 47 - Maybe put "gracedelay" in the database. 48 48 49 - Price multiplier/divisor which can be set on a per50 user or per user group basis.51 52 49 - Ink accounting ala PrintBill. 53 50 … … 92 89 - Documentation... 93 90 94 - Complete web administrative interface with graphical reports. 91 - Learn more bits of PHP to help with phpPyKotaAdmin, which 92 is a GREAT tool ! 95 93 96 94 - Group administrators (think quotagrpdmins for disk quotas).