Changeset 2054

Show
Ignore:
Timestamp:
02/13/05 23:02:29 (19 years ago)
Author:
jalet
Message:

Big database structure changes. Upgrade script is now included as well as
the new LDAP schema.
Introduction of the -o | --overcharge command line option to edpykota.
The output of repykota is more complete, but doesn't fit in 80 columns anymore.
Introduction of the new 'maxdenybanners' directive.

Location:
pykota/trunk
Files:
23 modified

Legend:

Unmodified
Added
Removed
  • pykota/trunk/bin/cupspykota

    r2028 r2054  
    2424# 
    2525# $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# 
    2633# Revision 1.84  2005/01/17 08:44:23  jalet 
    2734# Modified copyright years 
     
    501508            accountbanner = self.config.getAccountBanner(printer.Name) 
    502509            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) 
    507520  
    508521            self.printMoreInfo(user, printer, _("Job accounting begins.")) 
     
    511524            # handle starting banner pages during accounting 
    512525            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 
    519538        else :     
    520539            action = "ALLOW" 
     
    536555            # handle ending banner pages during accounting 
    537556            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 
    544569  
    545570            # stops accounting.  
     
    575600            # handle ending banner pages after accounting ends 
    576601            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                         
    582613            # Launches the post hook 
    583614            self.posthook(userpquota) 
     
    823854            try : 
    824855                status = subprocess.wait() 
    825             except OSError : # already dead     
     856            except OSError : # already dead : TODO : detect when abnormal 
    826857                status = 0 
    827858        if os.WIFEXITED(status) : 
  • pykota/trunk/bin/edpykota

    r2036 r2054  
    2424# 
    2525# $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# 
    2633# Revision 1.86  2005/01/21 14:40:01  jalet 
    2734# edpykota's --delete command line tool doesn't use "*" as its default argument 
     
    337344                       If both are to be set, separate them with a comma. 
    338345                       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. 
    339356   
    340357  -i | --ingroups g1[,g2...]  Puts the users into each of the groups 
     
    480497  When printing either on hplj1 or hplj2, print quota will also be  
    481498  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. 
    482513 
    483514This program is free software; you can redistribute it and/or modify 
     
    532563                (softlimit, hardlimit) = (hardlimit, softlimit) 
    533564             
     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                 
    534572        balance = options["balance"] 
    535573        if balance : 
     
    710748                            entrypquota.setUsage(used) 
    711749                             
     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                                 
    712755                        if balance : 
    713756                            if changed[entry.Name].get("balance") is None : 
     
    742785                     "printer" : "*", \ 
    743786                   } 
    744         short_options = "vhdc: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="] 
    746789         
    747790        # Initializes the command line tool 
     
    771814        options["hardreset"] = options["R"] or options["hardreset"]  
    772815        options["used"] = options["U"] or options["used"] 
     816        options["overcharge"] = options["o"] or options["overcharge"] 
    773817         
    774818        if options["help"] : 
     
    784828        elif options["noquota"] and (options["prototype"] or options["hardlimit"] or options["softlimit"]) : 
    785829            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"]) : 
    787831            raise PyKotaToolError, _("incompatible options, see help.") 
    788832        else : 
  • pykota/trunk/conf/pykota.conf.sample

    r2028 r2054  
    610610#                         printers, or "localhost" if not defined or not 
    611611#                         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# 
    612616 
    613617# PreHook : gets executed after being sure the user, printer and user quota 
     
    657661# accountbanner: Both 
    658662 
     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. 
     672maxdenybanners: 0 
     673 
    659674# StartingBanner : if defined will print a banner before the rest of the job  
    660675# is printed. The argument can be a printable file, or an executable file. 
  • pykota/trunk/FAQ

    r2047 r2054  
    1919    that all debug messages for PyKota will go to syslog's 
    2020    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. 
    2124   
    2225  * How can I limit my users to N pages per day (month/year) ? 
     
    4750      use the --printer command line argument as well. See 
    4851      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 ... 
    4958   
    5059  * Nothing prints when my printer is in PowerSave mode, what 
  • pykota/trunk/initscripts/ldap/pykota.schema

    r2028 r2054  
    187187        SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) 
    188188         
    189 # pykotaUserCoefficient 
    190 attributetype ( 1.3.6.1.4.1.16868.1.1.27 NAME 'pykotaUserCoefficient' 
    191         DESC 'Coefficient for a particular user, float' 
     189# pykotaOverCharge 
     190attributetype ( 1.3.6.1.4.1.16868.1.1.27 NAME 'pykotaOverCharge' 
     191        DESC 'OverCharging factor for a particular user, float' 
    192192        EQUALITY caseIgnoreIA5Match 
    193193        SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE ) 
     
    270270objectclass ( 1.3.6.1.4.1.16868.1.2.7 NAME 'pykotaAccountBalance' SUP top AUXILIARY 
    271271        DESC 'PyKota User account balance' 
    272         MAY  ( pykotaUserName $ pykotaBalance $ pykotaLifeTimePaid $ pykotaUserCoefficient $ pykotaPayments ) ) 
     272        MAY  ( pykotaUserName $ pykotaBalance $ pykotaLifeTimePaid $ pykotaOverCharge $ pykotaPayments ) ) 
    273273         
    274274# pykotaLastJob         
  • pykota/trunk/initscripts/postgresql/pykota-postgresql.sql

    r2037 r2054  
    2020-- 
    2121-- $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-- 
    2229-- Revision 1.15  2005/01/23 10:58:22  jalet 
    2330-- Added a few indexes for the database 
     
    106113                   lifetimepaid FLOAT DEFAULT 0.0, 
    107114                   limitby TEXT DEFAULT 'quota', 
    108                    coefficient FLOAT NOT NULL DEFAULT 1.0); 
     115                   overcharge FLOAT NOT NULL DEFAULT 1.0); 
    109116                    
    110117-- 
     
    135142                        hardlimit INT4, 
    136143                        datelimit TIMESTAMP, 
    137                         warned INT4 DEFAULT 0); -- not a boolean, will help stats 
     144                        warncount INT4 DEFAULT 0);  
    138145CREATE INDEX userpquota_u_id_ix ON userpquota (userid); 
    139146CREATE INDEX userpquota_p_id_ix ON userpquota (printerid); 
     
    176183                         hardlimit INT4, 
    177184                         datelimit TIMESTAMP); 
     185CREATE INDEX grouppquota_g_id_ix ON grouppquota (groupid); 
     186CREATE INDEX grouppquota_p_id_ix ON grouppquota (printerid); 
    178187CREATE UNIQUE INDEX grouppquota_up_id_ix ON grouppquota (groupid, printerid); 
    179188                         
     
    206215                           printerid INTEGER NOT NULL REFERENCES printers(id),  
    207216                           label TEXT NOT NULL,  
    208                            coefficient FLOAT NOT NULL DEFAULT 1.0,  
     217                           coefficient FLOAT DEFAULT 1.0,  
    209218                           CONSTRAINT coeffconstraint UNIQUE (printerid, label)); 
    210219 
     
    212221-- Set some ACLs                         
    213222-- 
    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; 
     223REVOKE ALL ON users, groups, printers, userpquota, grouppquota, groupsmembers, printergroupsmembers, jobhistory, payments, coefficients FROM public;                         
     224REVOKE 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; 
    216225 
    217226GRANT 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  
    5959  version of PyKota. 
    6060   
     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     
    6172  * An SQL script to upgrade a 1.18 PyKota Storage DataBase to 
    6273    1.19 is included. Launch it this way on the Quota Storage Server : 
  • pykota/trunk/NEWS

    r2044 r2054  
    2222PyKota NEWS : 
    2323        
     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         
    2445    - 1.21alpha23 : 
    2546     
  • pykota/trunk/po/fr_FR/pykota.po

    r2028 r2054  
    11201120msgid "Invalid modifier [%s] for --data command line option, see help." 
    11211121msgstr "" 
    1122 "Le modifier [%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, " 
    11231123"voir l'aide." 
    11241124 
     
    11261126msgid "Invalid modifier [%s] for --format command line option, see help." 
    11271127msgstr "" 
    1128 "Le modifier [%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." 
    11301130 
    11311131msgid "XML output is disabled because the jaxml module is not available." 
  • pykota/trunk/po/zh_TW/pykota.po

    r2043 r2054  
    2828"Project-Id-Version: PyKota v1.20\n" 
    2929"Report-Msgid-Bugs-To: alet@librelogiciel.com\n" 
    30 "POT-Creation-Date: 2005-01-25 09:03+0800\n" 
     30"POT-Creation-Date: 2004-11-25 10:16+0100\n" 
    3131"PO-Revision-Date: 2005-01-25 09:03+0800\n" 
    3232"Last-Translator: Tsang Yu Pong, Teddy, Wing Kwong College in Hong Kong," 
     
    3939#, python-format 
    4040msgid "" 
    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" 
    4243"\n" 
    4344"Generates banners.\n" 
     
    292293#, python-format 
    293294msgid "" 
    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" 
    295297"A Printers Manager for PyKota.\n" 
    296298"\n" 
     
    360362"  $ pkprinters --delete \"*\"\n" 
    361363"  \n" 
    362 "This will completely delete all printers and associated quota " 
     364"  This will completely delete all printers and associated quota " 
    363365"information,\n" 
    364366"  as well as their job history. USE WITH CARE !\n" 
     
    589591#, python-format 
    590592msgid "" 
    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" 
    592595"A tool to automate user account creation and initial balance setting.\n" 
    593596"\n" 
     
    664667#, python-format 
    665668msgid "" 
    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" 
    667671"\n" 
    668672"Dumps PyKota database's content.\n" 
     
    757761#, python-format 
    758762msgid "" 
    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" 
    760765"A Print Quota editor for PyKota.\n" 
    761766"\n" 
     
    10141019#, python-format 
    10151020msgid "" 
    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" 
    10171023"\n" 
    10181024"Generates print quota reports.\n" 
     
    10781084#, python-format 
    10791085msgid "" 
    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" 
    10811088"\n" 
    10821089"Sends mail to users over print quota.\n" 
     
    12551262"paid" 
    12561263msgstr "" 
    1257 "群組           已列印    警告限制    有效限制    結餘 寬限日期        付款總計       " 
    1258 "已繳付" 
    1259  
     1264"群組           已列印    警告限制    有效限制    結餘 寬限日期        付款總" 
     1265"計       已繳付" 
    12601266 
    12611267msgid "" 
     
    12631269"paid" 
    12641270msgstr "" 
    1265 "群組           已列印    警告限制    有效限制    結餘 寬限日期         付款總計       " 
    1266 "已繳付" 
     1271"群組           已列印    警告限制    有效限制    結餘 寬限日期         付款總" 
     1272"計       已繳付" 
    12671273 
    12681274msgid "unknown" 
     
    13141320"Unable to find user %s's account balance, applying default policy (%s) for " 
    13151321"printer %s" 
    1316 msgstr "" 
    1317 "未能尋找使用者 %s 的帳目結算,因此採用預設的政策(%s)於" 
    1318 "列印機 %s" 
     1322msgstr "未能尋找使用者 %s 的帳目結算,因此採用預設的政策(%s)於列印機 %s" 
    13191323 
    13201324#, python-format 
     
    13361340msgstr "使用者 %s 的列印配額於列印機 %s 經已超出配額" 
    13371341 
    1338 #, python 
    1339  
    13401342#, python-format 
    13411343msgid "Print Quota low for user %s on printer %s" 
     
    13451347msgstr "列印配額經已很低" 
    13461348 
    1347  
    13481349#, python-format 
    13491350msgid "Printing system %s, args=%s" 
     
    13741375"s) for printer %s" 
    13751376msgstr "" 
    1376 "列印機 %s 在PyKota系統內沒有登記,因此這台列印機" 
    1377 "套用external policy (%s) " 
     1377"列印機 %s 在PyKota系統內沒有登記,因此這台列印機套用external policy (%s) " 
    13781378 
    13791379#, python-format 
     
    13821382"for printer %s" 
    13831383msgstr "" 
    1384 "使用者 %s 在PyKota內沒有登記,因此這個使用者將會套用external policy(%s) " 
    1385 "於列印機 %s " 
     1384"使用者 %s 在PyKota內沒有登記,因此這個使用者將會套用external policy(%s) 於列" 
     1385"印機 %s " 
    13861386 
    13871387#, python-format 
     
    13891389"User %s doesn't have quota on printer %s in the PyKota system, applying " 
    13901390"external policy (%s) for printer %s" 
    1391 msgstr "" 
    1392 "使用者沒有列印配額於列印機 %s ,套用對外政策 (%s)" 
    1393 " 於列印機 %s" 
     1391msgstr "使用者沒有列印配額於列印機 %s ,套用對外政策 (%s) 於列印機 %s" 
    13941392 
    13951393#, python-format 
     
    13971395"External policy %s for printer %s produced an error. Job rejected. Please " 
    13981396"check PyKota's configuration files." 
    1399 msgstr "" 
    1400 "對外政策 %s 於列印機 %s 產生錯誤,列印工作被拒,請撿查PyKota的設定檔案" 
     1397msgstr "對外政策 %s 於列印機 %s 產生錯誤,列印工作被拒,請撿查PyKota的設定檔案" 
    14011398 
    14021399#, python-format 
    14031400msgid "" 
    14041401"Printer %s not registered in the PyKota system, applying default policy (%s)" 
    1405 msgstr "" 
    1406 "列印機 %s 沒有於PyKota系統內登記,套用預設的政策 (%s)" 
     1402msgstr "列印機 %s 沒有於PyKota系統內登記,套用預設的政策 (%s)" 
    14071403 
    14081404#, python-format 
     
    14101406"User %s not registered in the PyKota system, applying default policy (%s) " 
    14111407"for printer %s" 
    1412 msgstr "" 
    1413 "使用者 %s 沒有於PyKota系統內登記,套用預設的政策 (%s)" 
    1414 "於列印機 %s" 
     1408msgstr "使用者 %s 沒有於PyKota系統內登記,套用預設的政策 (%s)於列印機 %s" 
    14151409 
    14161410#, python-format 
     
    14181412"User %s doesn't have quota on printer %s in the PyKota system, applying " 
    14191413"default policy (%s)" 
    1420 msgstr "" 
    1421 "使用者 %s 沒有列印配額於列印機 %s,套用預設的政策 (%s)" 
     1414msgstr "使用者 %s 沒有列印配額於列印機 %s,套用預設的政策 (%s)" 
    14221415 
    14231416#, python-format 
    14241417msgid "" 
    14251418"Printer %s still not registered in the PyKota system, job will be rejected" 
    1426 msgstr "" 
    1427 "列印機 %s 依然沒有於PyKota系統內登記,列印工作要求被拒" 
     1419msgstr "列印機 %s 依然沒有於PyKota系統內登記,列印工作要求被拒" 
    14281420 
    14291421#, python-format 
     
    14311423"User %s still not registered in the PyKota system, job will be rejected on " 
    14321424"printer %s" 
    1433 msgstr "" 
    1434 "使用者 %s 依然沒有於PyKota系統內登記,列印工作要求被拒於" 
    1435 "列印機 %s" 
     1425msgstr "使用者 %s 依然沒有於PyKota系統內登記,列印工作要求被拒於列印機 %s" 
    14361426 
    14371427#, python-format 
     
    14391429"User %s still doesn't have quota on printer %s in the PyKota system, job " 
    14401430"will be rejected" 
    1441 msgstr "" 
    1442 "使用者 %s 依然沒有列印配額於列印機 %s 在PyKota系統,列印工作被拒" 
     1431msgstr "使用者 %s 依然沒有列印配額於列印機 %s 在PyKota系統,列印工作被拒" 
    14431432 
    14441433#, python-format 
     
    14821471"Couldn't retrieve printer %s's internal page counter either before or after " 
    14831472"printing." 
    1484 msgstr "" 
    1485 "不能恢復列印機 %s 的內存頁面計算器不論在列印的之前或之後" 
     1473msgstr "不能恢復列印機 %s 的內存頁面計算器不論在列印的之前或之後" 
    14861474 
    14871475#, python-format 
     
    15011489"download it from http://pysnmp.sourceforge.net" 
    15021490msgstr "" 
    1503 "要求內存的SNMP計算器,但找不到Python-SNMP" 
    1504 "請到http://pysnmp.sourceforge.net下載" 
     1491"要求內存的SNMP計算器,但找不到Python-SNMP請到http://pysnmp.sourceforge.net下" 
     1492"載" 
    15051493 
    15061494#, python-format 
     
    15321520"SNMP querying stage interrupted. Using latest value seen for internal page " 
    15331521"counter (%s) on printer %s." 
    1534 msgstr "" 
    1535 "SNMP查詢被中斷,使用最更新的數值來計算頁數" 
    1536 "計算器 (%s) 在列印機 %s 上" 
     1522msgstr "SNMP查詢被中斷,使用最更新的數值來計算頁數計算器 (%s) 在列印機 %s 上" 
    15371523 
    15381524#, python-format 
     
    15401526"PJL querying stage interrupted. Using latest value seen for internal page " 
    15411527"counter (%s) on printer %s." 
    1542 msgstr "" 
    1543 "PJL查詢被中斷,使用最更新的數值來計算頁數" 
    1544 "計算器 (%s) 在列印機 %s 上" 
     1528msgstr "PJL查詢被中斷,使用最更新的數值來計算頁數計算器 (%s) 在列印機 %s 上" 
    15451529 
    15461530#, python-format 
     
    15671551"Search base %s doesn't seem to exist. Probable misconfiguration. Please " 
    15681552"double check /etc/pykota/pykota.conf : %s" 
    1569 msgstr "" 
    1570 "%s 不存在,很可能是錯誤設定所致" 
    1571 "請撿查 /etc/pykota/pykota.conf : %s" 
     1553msgstr "%s 不存在,很可能是錯誤設定所致請撿查 /etc/pykota/pykota.conf : %s" 
    15721554 
    15731555#, python-format 
     
    15911573"No pykotaAccountBalance object found for user %s. Did you create LDAP " 
    15921574"entries manually ?" 
    1593 msgstr "未能為使用者 %s 尋找pkotaAccountBalance object,請問你是否已手動建立LDAP 紀錄?  " 
     1575msgstr "" 
     1576"未能為使用者 %s 尋找pkotaAccountBalance object,請問你是否已手動建立LDAP 紀" 
     1577"錄?  " 
    15941578 
    15951579#, python-format 
     
    15971581"Unable to find an existing objectClass %s entry with %s=%s to attach " 
    15981582"pykotaAccount objectClass" 
    1599 msgstr "未能尋找現存的objectclass %s 紀錄帶有 %s=%s" 
    1600 " 連繫到pykotaAccount objectClass " 
     1583msgstr "" 
     1584"未能尋找現存的objectclass %s 紀錄帶有 %s=%s 連繫到pykotaAccount objectClass " 
    16011585 
    16021586#, python-format 
  • pykota/trunk/pykota/config.py

    r1968 r2054  
    2222# 
    2323# $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# 
    2431# Revision 1.58  2004/12/02 22:01:58  jalet 
    2532# TLS is now supported with the LDAP backend 
     
    507514            return (mailto, args) 
    508515         
     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             
    509531    def getGraceDelay(self, printername) :     
    510532        """Returns the grace delay in days.""" 
  • pykota/trunk/pykota/reporter.py

    r1692 r2054  
    2222# 
    2323# $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# 
    2431# Revision 1.10  2004/09/02 10:09:30  jalet 
    2532# Fixed bug in LDAP user deletion code which didn't correctly delete the user's 
     
    8794    def getReportHeader(self) :         
    8895        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") 
    9097        else :     
    91             return _("User            used    soft    hard    balance grace         total       paid") 
     98            return _("User           overcharge   used    soft    hard    balance grace         total       paid warn") 
    9299             
    93100    def getPrinterRealPageCounter(self, printer) :         
     
    109116        balance = float(entry.AccountBalance or 0.0) 
    110117        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) 
    111126         
    112127        #balance 
     
    199214        strbalance = ("%5.2f" % balance)[:10] 
    200215        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) 
    202222         
    203223def openReporter(tool, reporttype, printers, ugnames, isgroup) : 
  • pykota/trunk/pykota/reporters/html.py

    r1278 r2054  
    2222# 
    2323# $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# 
    2431# Revision 1.8  2004/01/12 15:28:45  jalet 
    2532# Now can output the user's history on several printers at the same time. 
     
    8188                else :     
    8289                    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) 
    8491                if datelimit : 
    8592                    if datelimit == "DENY" : 
     
    8996                if (not self.tool.config.getDisableHistory()) and (not self.isgroup) : 
    9097                    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 "&nbsp;", 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 "&nbsp;", lifepagecounter, lifetimepaid, warncount)]))) 
    9299                total += pages 
    93100                totalmoney += money 
     
    95102            if total or totalmoney :         
    96103                (tpage, tmoney) = self.getTotals(total, totalmoney) 
    97                 self.report.append('<tr class="totals"><td colspan="7">&nbsp;</td><td align="right">%s</td><td align="right">%s</td></tr>' % (tpage, tmoney)) 
    98             self.report.append('<tr class="realpagecounter"><td colspan="7">&nbsp;</td><td align="right">%s</td></tr>' % self.getPrinterRealPageCounter(printer)) 
     104                self.report.append('<tr class="totals"><td colspan="8">&nbsp;</td><td align="right">%s</td><td align="right">%s</td><td>&nbsp;</td></tr>' % (tpage, tmoney)) 
     105            self.report.append('<tr class="realpagecounter"><td colspan="8">&nbsp;</td><td align="right">%s</td><td>&nbsp;</td></tr>' % self.getPrinterRealPageCounter(printer)) 
    99106            self.report.append('</table>') 
    100107        if self.isgroup :     
  • pykota/trunk/pykota/reporters/text.py

    r1257 r2054  
    2222# 
    2323# $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# 
    2431# Revision 1.9  2004/01/08 14:10:33  jalet 
    2532# Copyright year changed. 
     
    7885            self.report.append('-' * len(header)) 
    7986            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)) 
    8289                total += pages 
    8390                totalmoney += money 
     
    8592            if total or totalmoney :         
    8693                (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)) 
    8996            self.report.append("")         
    9097        if self.isgroup :     
  • pykota/trunk/pykota/storage.py

    r2030 r2054  
    2222# 
    2323# $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# 
    2431# Revision 1.67  2005/01/18 19:47:50  jalet 
    2532# Big bug fix wrt the datelimit attribute 
     
    276283        self.LifeTimePaid = None 
    277284        self.Email = None 
     285        self.OverCharge = 1.0 
    278286        self.Payments = [] # TODO : maybe handle this smartly for SQL, for now just don't retrieve them 
    279287         
     
    308316            self.LimitBy = limitby 
    309317         
     318    def setOverChargeFactor(self, factor) :     
     319        """Sets the user's overcharging coefficient.""" 
     320        self.parent.writeUserOverCharge(self, factor) 
     321        self.OverCharge = factor 
     322         
    310323    def delete(self) :     
    311324        """Deletes an user from the Quota Storage.""" 
     
    357370        self.PricePerJob = None 
    358371        self.Description = None 
     372        self.Coefficients = None 
    359373         
    360374    def __getattr__(self, name) :     
     
    424438        self.HardLimit = None 
    425439        self.DateLimit = None 
     440        self.WarnCount = None 
    426441         
    427442    def __getattr__(self, name) :     
     
    445460        self.HardLimit = hardlimit 
    446461        self.DateLimit = None 
     462        self.WarnCount = 0 
    447463         
    448464    def setUsage(self, used) : 
     
    454470                self.parent.increaseUserPQuotaPagesCounters(self, vused) 
    455471                self.parent.writeUserPQuotaDateLimit(self, None) 
     472                self.parent.writeUserPQuotaWarnCount(self, 0) 
    456473            except PyKotaStorageError, msg :     
    457474                self.parent.rollbackTransaction() 
     
    465482            self.PageCounter = self.LifePageCounter = vused 
    466483        self.DateLimit = None 
     484        self.WarnCount = 0 
    467485 
     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         
    468491    def reset(self) :     
    469492        """Resets page counter to 0.""" 
     
    482505        totalprice = 0.0     
    483506        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 
    488517             
    489518    def increasePagesUsage(self, jobsize) : 
     
    589618        self.JobOptions = None 
    590619        self.JobHostName = None 
     620        self.JobMD5Sum = None 
     621        self.JobPages = None 
     622        self.JobBillingCode = None 
    591623         
    592624    def __getattr__(self, name) :     
  • pykota/trunk/pykota/storages/ldapstorage.py

    r2042 r2054  
    2222# 
    2323# $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# 
    2431# Revision 1.99  2005/01/24 17:44:17  jalet 
    2532# Same fix for group print quota entries wrt LDAP performance 
     
    647654        """Extracts user information given its name.""" 
    648655        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"]) 
    650657        if result : 
    651658            fields = result[0][1] 
    652659            user.ident = result[0][0] 
    653660            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]) 
    662664            result = self.doSearch("(&(objectClass=pykotaAccountBalance)(|(pykotaUserName=%s)(%s=%s)))" % (username, self.info["balancerdn"], username), ["pykotaBalance", "pykotaLifeTimePaid", "pykotaPayments"], base=self.info["balancebase"]) 
    663665            if not result : 
     
    695697            group.ident = result[0][0] 
    696698            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] 
    702700            group.AccountBalance = 0.0 
    703701            group.LifeTimePaid = 0.0 
     
    717715            printer.ident = result[0][0] 
    718716            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]) 
    721719            printer.uniqueMember = fields.get("uniqueMember", []) 
    722720            printer.Description = self.databaseToUserCharset(fields.get("description", [""])[0])  
     
    732730            else :     
    733731                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) 
    735733            if result : 
    736734                fields = result[0][1] 
    737735                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]) 
    740739                userpquota.SoftLimit = fields.get("pykotaSoftLimit") 
    741740                if userpquota.SoftLimit is not None : 
     
    815814            result = None 
    816815            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) 
    818817            except PyKotaStorageError :     
    819818                pass # Last job entry exists, but job probably doesn't exist anymore.  
     
    823822                lastjob.JobId = fields.get("pykotaJobId")[0] 
    824823                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]) 
    826825                try : 
    827826                    lastjob.JobSize = int(fields.get("pykotaJobSize", [0])[0]) 
     
    839838                lastjob.JobHostName = fields.get("pykotaHostName", [""])[0] 
    840839                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] 
    841843                date = fields.get("createTimestamp", ["19700101000000"])[0] 
    842844                year = int(date[:4]) 
     
    924926        else : 
    925927           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) 
    927929        if result : 
    928930            for (userquotaid, fields) in result : 
     
    930932                userpquota = StorageUserPQuota(self, user, printer) 
    931933                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]) 
    934937                userpquota.SoftLimit = fields.get("pykotaSoftLimit") 
    935938                if userpquota.SoftLimit is not None : 
     
    990993                       "pykotaUserName" : user.Name, 
    991994                       "pykotaLimitBy" : (user.LimitBy or "quota"), 
     995                       "pykotaOverCharge" : str(user.OverCharge), 
    992996                    }    
    993997                        
     
    10481052        newfields = {  
    10491053                      "pykotaGroupName" : group.Name, 
    1050                       "pykotaLimitBY" : (group.LimitBy or "quota"), 
     1054                      "pykotaLimitBy" : (group.LimitBy or "quota"), 
    10511055                    }  
    10521056        mustadd = 1 
     
    11021106                   "pykotaPageCounter" : "0", 
    11031107                   "pykotaLifePageCounter" : "0", 
     1108                   "pykotaWarnCount" : "0", 
    11041109                 }  
    11051110        if self.info["userquotabase"].lower() == "user" : 
     
    11411146        self.doModify(printer.ident, fields) 
    11421147         
     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         
    11431155    def writeUserLimitBy(self, user, limitby) :     
    11441156        """Sets the user's limiting factor.""" 
     
    11831195                   "pykotaLifePageCounter" : str(newlifepagecounter), 
    11841196                   "pykotaDateLimit" : None, 
     1197                   "pykotaWarnCount" : "0", 
    11851198                 }   
    11861199        return self.doModify(userpquota.ident, fields)          
     
    12461259                   "pykotaHostName" : str(clienthost),  
    12471260                   "pykotaJobSizeBytes" : str(jobsizebytes), 
     1261                   # TODO : add the 3 missing fields 
    12481262                 } 
    12491263        if (not self.disablehistory) or (not printer.LastJob.Exists) : 
     
    12781292                   "pykotaHardLimit" : str(hardlimit), 
    12791293                   "pykotaDateLimit" : "None", 
     1294                   "pykotaWarnCount" : "0", 
    12801295                 } 
    12811296        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)          
    12821311         
    12831312    def writeGroupPQuotaLimits(self, grouppquota, softlimit, hardlimit) : 
  • pykota/trunk/pykota/storages/sql.py

    r2030 r2054  
    2222# 
    2323# $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# 
    2431# Revision 1.64  2005/01/18 19:47:50  jalet 
    2532# Big bug fix wrt the datelimit attribute 
     
    273280            user.LifeTimePaid = fields.get("lifetimepaid") 
    274281            user.Email = fields.get("email") 
     282            user.OverCharge = fields.get("overcharge", 1.0) 
    275283            user.Exists = 1 
    276284        return user 
     
    317325                userpquota.HardLimit = fields.get("hardlimit") 
    318326                userpquota.DateLimit = fields.get("datelimit") 
     327                userpquota.WarnCount = fields.get("warncount") 
    319328                userpquota.Exists = 1 
    320329        return userpquota 
     
    359368            lastjob.JobHostName = fields.get("hostname") 
    360369            lastjob.JobSizeBytes = fields.get("jobsizebytes") 
     370            lastjob.JobMD5Sum = fields.get("md5sum") 
     371            lastjob.JobPages = fields.get("pages") 
     372            lastjob.JobBillingCode = fields.get("billingcode") 
    361373            lastjob.Exists = 1 
    362374        return lastjob 
     
    374386                user.LifeTimePaid = record.get("lifetimepaid") 
    375387                user.Email = record.get("email") 
     388                user.OverCharge = record.get("overcharge") 
    376389                user.Exists = 1 
    377390                groupmembers.append(user) 
     
    423436        """Returns the list of users who uses a given printer, along with their quotas.""" 
    424437        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)) 
    426439        if result : 
    427440            for record in result : 
     
    433446                    user.LifeTimePaid = record.get("lifetimepaid") 
    434447                    user.Email = record.get("email")  
     448                    user.OverCharge = record.get("overcharge") 
    435449                    user.Exists = 1 
    436450                    userpquota = StorageUserPQuota(self, user, printer) 
     
    441455                    userpquota.HardLimit = record.get("hardlimit") 
    442456                    userpquota.DateLimit = record.get("datelimit") 
     457                    userpquota.WarnCount = record.get("warncount") 
    443458                    userpquota.Exists = 1 
    444459                    usersandquotas.append((user, userpquota)) 
     
    466481    def addUser(self, user) :         
    467482        """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))) 
    469484        return self.getUser(user.Name) 
    470485         
     
    503518        self.doModify("UPDATE printers SET description=%s WHERE id=%s" % (self.doQuote(description), self.doQuote(printer.ident))) 
    504519         
     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         
    505524    def writeUserLimitBy(self, user, limitby) :     
    506525        """Sets the user's limiting factor.""" 
     
    521540    def increaseUserPQuotaPagesCounters(self, userpquota, nbpages) :     
    522541        """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))) 
    524543        
    525544    def writeUserPQuotaPagesCounters(self, userpquota, newpagecounter, newlifepagecounter) :     
    526545        """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))) 
    528547        
    529548    def decreaseUserAccountBalance(self, user, amount) :     
    530549        """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))) 
    532551        
    533552    def writeUserAccountBalance(self, user, newbalance, newlifetimepaid=None) :     
     
    565584    def writeUserPQuotaLimits(self, userpquota, softlimit, hardlimit) : 
    566585        """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)) 
    568595         
    569596    def writeGroupPQuotaLimits(self, grouppquota, softlimit, hardlimit) : 
     
    620647                job.JobHostName = fields.get("hostname") 
    621648                job.JobSizeBytes = fields.get("jobsizebytes") 
     649                job.JobMD5Sum = fields.get("md5sum") 
     650                job.JobPages = fields.get("pages") 
     651                job.JobBillingCode = fields.get("billingcode") 
    622652                job.UserName = fields.get("username") 
    623653                job.PrinterName = fields.get("printername") 
  • pykota/trunk/pykota/tool.py

    r2008 r2054  
    2222# 
    2323# $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# 
    2431# Revision 1.148  2005/01/06 23:24:21  jalet 
    2532# Regain priviledge the time to open the job's data file when printing in 
     
    10121019                return action         
    10131020            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" 
    10221024                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 
    10261037                return action     
    10271038        else : 
     
    11061117        if action.startswith("POLICY_") : 
    11071118            action = action[7:] 
     1119             
    11081120        if action == "DENY" : 
    11091121            adminmessage = _("Print Quota exceeded for user %s on printer %s") % (user.Name, printer.Name) 
     
    12861298    def exportUserInfo(self, userpquota) : 
    12871299        """Exports user information to the environment.""" 
     1300        os.environ["PYKOTAOVERCHARGE"] = str(userpquota.User.OverCharge) 
    12881301        os.environ["PYKOTALIMITBY"] = str(userpquota.User.LimitBy) 
    12891302        os.environ["PYKOTABALANCE"] = str(userpquota.User.AccountBalance or 0.0) 
     
    12941307        os.environ["PYKOTAHARDLIMIT"] = str(userpquota.HardLimit) 
    12951308        os.environ["PYKOTADATELIMIT"] = str(userpquota.DateLimit) 
     1309        os.environ["PYKOTAWARNCOUNT"] = str(userpquota.WarnCount) 
    12961310         
    12971311        # not really an user information, but anyway 
  • pykota/trunk/pykota/version.py

    r2044 r2054  
    2222# 
    2323 
    24 __version__ = "1.21alpha23_unofficial" 
     24__version__ = "1.21alpha24_unofficial" 
    2525 
    2626__doc__ = """PyKota : a complete Printing Quota Solution for CUPS and LPRng.""" 
  • pykota/trunk/README

    r2051 r2054  
    250250  You may learn more about PyKota, if it fits your own organization, 
    251251  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 : 
    253253   
    254254    http://archive.macosxlabs.org/forum/webcrossing_archive/documentation/Pykota_and_CUPS/Pykota_and_CUPS.html 
     
    610610     
    611611    which will print quota usage for all users on all printers, 
    612     along with totals, if you are the root user. If you are 
     612    along with totals, if you are a PyKota Administator. If you are 
    613613    a regular user, only your own quota report will be produced. 
    614614     
     
    631631 
    632632  - Kanakorn Horsiritham developped phpPykotaAdmin which is  
    633     a web based administrative GUI : 
     633    a web based database independant administrative GUI : 
    634634   
    635635      http://opensource.psu.ac.th/~kanakorn/mambo/ 
  • pykota/trunk/TODO

    r2028 r2054  
    3636        - Better --prototype option in edpykota 
    3737         
    38         - Web enabled pykotme and dumpykota. 
     38        - Web enabled pykotme. 
    3939         
    4040        - Add an MD5 checksum of the job's datas to the 
     
    4747        - Maybe put "gracedelay" in the database. 
    4848         
    49         - Price multiplier/divisor which can be set on a per 
    50           user or per user group basis. 
    51  
    5249        - Ink accounting ala PrintBill. 
    5350         
     
    9289        - Documentation... 
    9390           
    94         - Complete web administrative interface with graphical reports. 
     91        - Learn more bits of PHP to help with phpPyKotaAdmin, which 
     92          is a GREAT tool ! 
    9593        
    9694        - Group administrators (think quotagrpdmins for disk quotas).