From 5cf766ec928deac31035c02890daed631fa67aa1 Mon Sep 17 00:00:00 2001 From: Sergey Morozov Date: Fri, 18 Apr 2014 23:43:54 +0400 Subject: [PATCH] Moved to Git repo from PST server --- .htaccess-example | 36 +++++ config-example.py | 21 +++ images/left.jpg | Bin 0 -> 1216 bytes images/printer.jpg | Bin 0 -> 821 bytes images/right.jpg | Bin 0 -> 1226 bytes images/trash.gif | Bin 0 -> 1407 bytes images/trash.jpg | Bin 0 -> 1600 bytes images/trash.png | Bin 0 -> 5643 bytes include/.htaccess | 2 + include/database.py | 170 +++++++++++++++++++++ include/functions.py | 14 ++ include/webInterface.py | 329 ++++++++++++++++++++++++++++++++++++++++ index.py | 28 ++++ print.py | 28 ++++ tools/.htaccess | 2 + tools/dbinit.py | 51 +++++++ tools/shell.py | 23 +++ view-all.py | 28 ++++ 18 files changed, 732 insertions(+) create mode 100644 .htaccess-example create mode 100644 config-example.py create mode 100644 images/left.jpg create mode 100644 images/printer.jpg create mode 100644 images/right.jpg create mode 100644 images/trash.gif create mode 100644 images/trash.jpg create mode 100644 images/trash.png create mode 100644 include/.htaccess create mode 100644 include/database.py create mode 100644 include/functions.py create mode 100644 include/webInterface.py create mode 100644 index.py create mode 100644 print.py create mode 100644 tools/.htaccess create mode 100755 tools/dbinit.py create mode 100755 tools/shell.py create mode 100644 view-all.py diff --git a/.htaccess-example b/.htaccess-example new file mode 100644 index 0000000..c860fb1 --- /dev/null +++ b/.htaccess-example @@ -0,0 +1,36 @@ +Options +ExecCGI +AddHandler wsgi-script .py +RewriteEngine On +DirectoryIndex index.py + +RewriteCond %{REQUEST_URI} /\.svn/ +RewriteRule . - [F] + + Order allow,deny + Deny from all + + + Order allow,deny + Deny from all + + + Order allow,deny + Allow from all + + +#AuthLDAPBindDN "" +#AuthLDAPBindPassword "" +#AuthLDAPURL "ldap://:3268/?sAMAccountName?sub" +#AuthType Basic +#AuthName "" +#AuthBasicProvider ldap +#AuthUserFile /dev/null +AuthName "Kerberos Login" +AuthType Kerberos +Krb5Keytab /path/to/krb/keytab +KrbAuthRealm +KrbMethodNegotiate off +KrbSaveCredentials off +KrbVerifyKDC off + +Require valid-user diff --git a/config-example.py b/config-example.py new file mode 100644 index 0000000..d715fa8 --- /dev/null +++ b/config-example.py @@ -0,0 +1,21 @@ +''' +Created on 29.11.2010 + +@author: morozov +''' + +# Database server settings +mysql_server = 'localhost' +mysql_database = 'businesstrips' +mysql_user = 'businesstrips' +mysql_password = 'businessTripsSecret' +mysql_port = 3306 + +# Permissions +allow_delete_any_record = ['user1', 'user2', 'user3'] + +# Default values +default_start_time_hour = '9' +default_start_time_minute = '30' +default_end_time_hour = '18' +default_end_time_minute = '15' diff --git a/images/left.jpg b/images/left.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ba2bb29a3f38e4cb7319434d903d6092c6538ea0 GIT binary patch literal 1216 zcmex=g%x#K0lUDI&^c zXj-yG5vWoOWInANtJ6Uq=<=Nr4KPzgk4=on@Eo8rP zV&{DBfGI}|-@MxJ`I_z8i6Jv?mEEyh>as57?q3d`)j=UWH#aN(nkg~!)e=UJ!#TTL zy=T6#d+wp+RliFDRF++_dCaWl{H^}-f;S^<=g8|bG2XJ?kT>$ zUFKt7#q*xJd;VtMH_n*4bp4h90SUp_xYc{Ew|9v13bZ-M{Ixg|_UKrrs2kB`j%wea8kPq#e&F233C(=NI7)yiUzNHekJzbCo9`}KFHc2%Kp==V7xo33}Y zlwaGfw({%g9gJP;Pe>M>vYjlZ*!T3=N3+{29)0JDF1*Q~6{(#Px<6!B)QZEMKUvNn zJgM|rcg+h`Gvza0(F_mc_q^DV`<>^HUr>DHrft1CbB$W>F1RfDlYQpb8;&w8`{p*P z>|#GLwcP0q&ymcpiRVM!*xL!*Y14MQ?-V|#Xz2o*?YB;a_B`Je`;aR)^VFnAVN(}t z`4!H&+z|h9@&3iaf8PG!v;Fc*=aOyfMvq%^JA~J~T-%*6?VbMCO}c)KYuBz+Te>ai zJa2>3Y0p*BMVJd`ro{?OH|m#3QB82X~RxzyEi z6dUC>DZV()$obd7?p8%{-Xq@TX<2W|#3vqmuK(I>>z%Dd{~1hQO%#U3Aw+GOPc;2>^q-*LF+QIY@e%pA1&LvWZT4vMOkKtWlE;D{CHqI zo$rMFsvQqc%f4U~UfrAbdzH+)wYwa;6Sq!mIn{Y#--S6P$7Yx7b}V(Yet9+aNYUx! zjVg=3i!5U(-=VwCSN=w^V{xxvS=Qam^E>8sSeX}HF?%aE-;mo@AmqwcFROwVYU*rL zr*rl!Y@DZXWwC~)=XbrW?H-ja$$FEniOyMh_84I=l9%%eiIU zJ^#X%2X|fH@NLn}*%R8P_V=!u=(oZzEIKW2NpX8P{~AYAu?Gt_+|UTF&qy~Gu2}xd z>e_*K4rY6${a^0c5-N2&d`tLQ#$C-q#=+ORmUei%U*`_k*s4$@$g3ggrDfqXu~|CW zZC`sw=I+x{X4;<@Yzeb@Zl|;C`N!LT>g6pz&+oUhvnf2T8I%xwXugoDvR6s%@~s=L zWp>UDT-~+%_Pg6c=QY)A>#XV-jz+)R6vi>@O3j`#Je99|ySif>-Wk4OmKI{RTR7vu N%VeM_D*pd(0su(t7vul{ literal 0 HcmV?d00001 diff --git a/images/right.jpg b/images/right.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b8305d3a968644cd131706c52ccf673ca31aa216 GIT binary patch literal 1226 zcmex=z*vb`Az1PC;Q&aS=nH zDp8=(2+bfCI~!0~SrDj^39K6`3p9p>m5p6ch(k$4RME)s|1Aa{W=5b(m<1W^8S3SN zrmg##?vr*M@Aj}Pa$-M+b8owY!Yi#w7#^v1RWr*aOx(!8+D z<@k#JjVC6Z;o+)1a^?un#82mb++~%z`e6en_f7AqQOg}B>2j@5I-mwLAP)mv7T&@8G;`OV)A) zh4wtFXI(G)XJzD%wgf4aQ>kV4np4sY{5E@PXgyr=!Fk_NuS};W9;usFah$s1d8;Vk z;3Jo)kbisawmdr3Feg!Jad!6E$Ln6rP7aAmUN`I4dx@D_{GP)(uPdAB zguBOaIm5z9ABB?Gb$N9pHwGCs%=sz4&YDv(wsqlV zf%8tEZRQB{8&exWDV zzgW2Z?b4@O9)^7dU5}X5A{72JX#SX<|BNSJI>A(J-TVi6(>7J^ncLj3vhS!LTh`2r<~9nIZ4rFW-Fnc;OADZ_nQS-L~uLM(&J8-Y=)k&Tjr8e=eS> zMe&V|!Phg1@(rh7J{IR$KBqwIgPGFtDMf;pUfX87U*00MY{RvyA6H$8^0BxOx%wZ-e;>eo1 z@u*1PZExisgEvcg4G!}v@*17?@Xj@xvXIj&xF@MzcuOq5@S>#P{zZAa^FlW4p0d^U z#+GDeBW;eETw4*Te}W4P7>AP YnC>-UlgiXU+w)&jr{AoX&oEK1PP856}<=p zYabnt77)?{2fYalW+5Pl7#V;X80znE-a-bB#u8r~lvrY|huARF@=9@irzwk$5_9wy)+ zBHtk>*d-s&Cnw<}Bcn7j>mecZ9wp)=B*85$>mn$VJ2>JcD&r<4>?0|5L`TamEtNew z?j<90Mn~->D%&b9Mt(iB3-DH8uA! zF!nJv-8en(G&74&PtZL+_cJ%>I5)~bLfAY(@HRU6G&u1$HS#z+`ZhVUN=D;7JNq{} z{Wv=QIy;|KROdoOxKB`_R#wzWN!LwG?np_-R8qTGR@+cdy;@iKQc>$ySj}N!*-6vK`|a-U_4oMm@%{Jq`~CX) z|Ns8~{Qv*|A^s6Va%Ew3Wn>_CX>@2HM@dak03rDV0SW;B04x9i001BWAOHXe{s8|8 z97wRB!Gj17HdDrI+O=!bpgoJ0u;QvaUYaaHLZwR=En2#mfph6qMS_)j2naA@1{Ez~ z*suwsg$j`qC{Bzybn;&X03BrL=nG}jz;f(RBofJn)bMG6oeEJR3H&|*)NiVdEu>SF{11`aQ56e(ik z1&0eDjtp9bV?)IV6s)uwCQKJ8M}Z0z3S>!@E@Hn9!PwB?atatY?93`A4cj(w-m+OU zW=jkO1FTyojF1AylQVYsc%tQrQY11sU^oCCyk~JMYyNN=C5w}vGf%Moz=+VGe0l3Q zqO6HTiPbGuhRU3Y0)vA2^Cyd|XYYPes6$cEXWxD3?MDf7;qbE$H6GwFpm_zZH_9T> z_@j+D{dDrdgZNdXUv`w(a*sM_yg|=BqCjw;a2}?&1|V)AqYp5Iyzvb>8#u6Hfo;^` z3o4&@V#ps+MBq#D zNwTP=aY-a&&l8a30Z1HJP*8w8)f7OUnh3%6#22p2Lryo`>_Wyj=8RJhBWd;oTNHMD zam+gL;IqsV@VIjhFM29j5p38+LI@s|7!pYtg5=-;1bb%LCk{!Wj&jR;Ls}7q6CCn+ z5UA_5cMB*(o)H~~JqhH5f$jnOhp_dTXIZfV_3EA}Ly~dpfY2J02q&;);s+gA43Pr@ N*_LbWxd{aX06WESQ#Akp literal 0 HcmV?d00001 diff --git a/images/trash.jpg b/images/trash.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5d28ae6d54353c43e674ba0d59da80721a1aa0a2 GIT binary patch literal 1600 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 literal 0 HcmV?d00001 diff --git a/include/.htaccess b/include/.htaccess new file mode 100644 index 0000000..cb24fd7 --- /dev/null +++ b/include/.htaccess @@ -0,0 +1,2 @@ +Order allow,deny +Deny from all diff --git a/include/database.py b/include/database.py new file mode 100644 index 0000000..862f395 --- /dev/null +++ b/include/database.py @@ -0,0 +1,170 @@ +''' +Created on 29.11.2010 + +@author: morozov +''' + +import sys, MySQLdb, datetime +sys.path.append('.') +import functions +config = functions.readConfig() + +class dbOperations(): + class journalRecord(): + def __init__(self, + key = None, + name = None, + position = None, + department = None, + date = None, + startTime = None, + endTime = None, + description = None, + chief = None, + userName = None): + self.key = key + self.name = name + self.position = position + self.department = department + self.date = date + self.startTime = startTime + self.endTime = endTime + self.description = description + self.chief = chief + self.userName = userName + + def __str__(self): + return('key: \'%s\'\n' + 'name: \'%s\'\n' + 'position: \'%s\'\n' + 'department: \'%s\'\n' + 'date: \'%s\'\n' + 'startTime: \'%s\'\n' + 'endTime: \'%s\'\n' + 'description: \'%s\'\n' + 'chief: \'%s\'\n' + 'userName: \'%s\'\n' % (self.key, + self.name, + self.position, + self.department, + self.date, + self.startTime, + self.endTime, + self.description, + self.chief, + self.userName)) + + def __repr__(self): + return(self.__str__()) + + def __init__(self, dbname, user, password, host='localhost', port=3306): + ''' + Constructor + ''' + + self.db = MySQLdb.connect( + host = host, + user = user, + passwd = password, + db = dbname, + port = int(port), + connect_timeout = 10) + self.cursor = self.db.cursor() + + def setProperty(self, userName, propertyName, propertyValue): + self.delProperty(userName, propertyName) + q = "INSERT INTO `user_settings` (`username`, `setting`, `value`) VALUES ('%s', '%s', '%s')" % (userName, propertyName, propertyValue) + self.cursor.execute(q) + self.db.commit() + + def getProperty(self, userName, propertyName): + q = "SELECT `value` FROM `user_settings` WHERE `username` = '%s' AND `setting` = '%s'" % (userName, propertyName) + self.cursor.execute(q) + result = self.cursor.fetchone() + self.db.commit() + try: + return(result[0]) + except: + return(None) + + def delProperty(self, userName, propertyName): + q = "DELETE FROM `user_settings` WHERE `username` = '%s' AND `setting` = '%s'" % (userName, propertyName) + self.cursor.execute(q) + self.db.commit() + + def journalGetRecord(self, key): + self.cursor.execute("SELECT `key`, `name`, `position`, `department`, `date`, `start_time`, `end_time`, `description`, `chief`, `username` FROM `journal` WHERE `key` = '%s' LIMIT 1" % key) + record = self.cursor.fetchone() + self.db.commit() + try: + result = self.journalRecord(key = record[0], + name = record[1], + position = record[2], + department = record[3], + date = record[4], + startTime = (datetime.datetime.min + record[5]).time(), + endTime = (datetime.datetime.min + record[6]).time(), + description = record[7], + chief = record[8], + userName = record[9]) + except TypeError: + return(None) + else: + return(result) + + def journalGetRecords(self, date): + self.cursor.execute("SELECT `key`, `name`, `position`, `department`, `date`, `start_time`, `end_time`, `description`, `chief`, `username` FROM `journal` WHERE `date` = '%s' ORDER BY `start_time`, `key`" % date) + rows = self.cursor.fetchall() + self.db.commit() + result = [] + for i in xrange(len(rows)): + result.append(self.journalRecord(key = rows[i][0], + name = rows[i][1], + position = rows[i][2], + department = rows[i][3], + date = rows[i][4], + startTime = (datetime.datetime.min + rows[i][5]).time(), + endTime = (datetime.datetime.min + rows[i][6]).time(), + description = rows[i][7], + chief = rows[i][8], + userName = rows[i][9])) + return(result) + + def journalSaveRecord(self, journalRecord): + self.cursor.execute("INSERT INTO `journal` (`name`, `position`, `department`, `date`, `start_time`, `end_time`, `description`, `chief`, `username`) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)", (journalRecord.name, journalRecord.position, journalRecord.department, journalRecord.date, journalRecord.startTime, journalRecord.endTime, journalRecord.description, journalRecord.chief, journalRecord.userName)) + self.db.commit() + + def journalDeleteRecord(self, userName, key): + if self.journalCheckDeletePermissions(userName, key): + q = "DELETE FROM `journal` WHERE `key` = '%s'" % key + self.cursor.execute(q) + self.db.commit() + else: + pass + + def journalCheckDeletePermissions(self, userName, key): + record = self.journalGetRecord(key) + self.db.commit() + if userName == record.userName or userName in config.allow_delete_any_record: + return(True) + else: + return(False) + + def journalListDays(self, limit = None): + if limit == None: + limit = '' + else: + limit = 'LIMIT %s' % limit + q = "SELECT DISTINCT `date` FROM `journal` ORDER BY `date` DESC %s" % limit + self.cursor.execute(q) + days = self.cursor.fetchall() + self.db.commit() + result = [] + for i in xrange(len(days)): + result.append(days[i][0]) + return(result) + + def close(self): + self.cursor.close() + self.db.close() + pass diff --git a/include/functions.py b/include/functions.py new file mode 100644 index 0000000..360d82b --- /dev/null +++ b/include/functions.py @@ -0,0 +1,14 @@ +''' +Created on 26.11.2010 + +@author: morozov +''' + +import os, sys +includedir = os.path.dirname(__file__) +serverdir = includedir + os.sep + '..' +sys.path.append(serverdir) + +def readConfig(): + import config + return config diff --git a/include/webInterface.py b/include/webInterface.py new file mode 100644 index 0000000..0ee09ff --- /dev/null +++ b/include/webInterface.py @@ -0,0 +1,329 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +''' +Created on 17.12.2010 + +@author: morozov +''' + +import sys, cgi, datetime +sys.path.append('.') +import functions +from wsgiref.util import application_uri + +config = functions.readConfig() + +class pageParts(object): + ''' + classdocs + ''' + + + def __init__(self, environ, db): + ''' + Constructor + ''' + self.environ = environ + self.userName = environ['REMOTE_USER'] + self.fieldStorage = cgi.FieldStorage(fp = environ['wsgi.input'], environ = environ, keep_blank_values = 1) + self.db = db + self.appUrl = application_uri(environ) + self.requestUri = environ['REQUEST_URI'] + self.errStatus = False + self.errMsg = '' + self.now = datetime.datetime.now() + + if self.fieldStorage.has_key('year') and self.fieldStorage.has_key('month') and self.fieldStorage.has_key('day'): + try: + self.journalDate = datetime.date(year = int(self.fieldStorage.getfirst('year')), month = int(self.fieldStorage.getfirst('month')), day = int(self.fieldStorage.getfirst('day'))) + except ValueError: + self.journalDate = self.now.date() + else: + self.journalDate = self.now.date() + + try: + self.previousDay = self.journalDate - datetime.timedelta(days = 1) + except OverflowError: + self.previousDayError = True + else: + self.previousDayError = False + try: + self.nextDay = self.journalDate + datetime.timedelta(days = 1) + except OverflowError: + self.nextDayError = True + else: + self.nextDayError = False + self.tomorrow = datetime.datetime.now().date() + datetime.timedelta(days = 1) + + if self.fieldStorage.has_key('newName')\ + and self.fieldStorage.has_key('newPosition')\ + and self.fieldStorage.has_key('newDepartment')\ + and self.fieldStorage.has_key('newStartTimeHour')\ + and self.fieldStorage.has_key('newStartTimeMinute')\ + and self.fieldStorage.has_key('newEndTimeHour')\ + and self.fieldStorage.has_key('newEndTimeMinute')\ + and self.fieldStorage.has_key('newDescription')\ + and self.fieldStorage.has_key('newChief'): + try: + newRecord = self.db.journalRecord(name = self.fieldStorage.getfirst('newName'), + position = self.fieldStorage.getfirst('newPosition'), + department = self.fieldStorage.getfirst('newDepartment'), + date = self.journalDate, + startTime = datetime.time(hour = int(self.fieldStorage.getfirst('newStartTimeHour')), + minute = int(self.fieldStorage.getfirst('newStartTimeMinute'))), + endTime = datetime.time(hour = int(self.fieldStorage.getfirst('newEndTimeHour')), + minute = int(self.fieldStorage.getfirst('newEndTimeMinute'))), + description = self.fieldStorage.getfirst('newDescription'), + chief = self.fieldStorage.getfirst('newChief'), + userName = self.userName) + for value in newRecord.name, newRecord.position, newRecord.department, newRecord.description: + if len(value) == 0: + raise ValueError + except ValueError: + self.errStatus = True + self.errMsg = 'Введены неверные данные. Заполняйте форму внимательнее.' + else: + self.db.setProperty(self.userName, 'latestName', newRecord.name) + self.db.setProperty(self.userName, 'latestPosition', newRecord.position) + self.db.setProperty(self.userName, 'latestDepartment', newRecord.department) + self.db.setProperty(self.userName, 'latestChief', newRecord.chief) + self.db.journalSaveRecord(newRecord) + + if self.fieldStorage.has_key('delete'): + try: + self.db.journalDeleteRecord(self.userName, int(self.fieldStorage.getfirst('delete'))) + except: + self.errStatus = True + self.errMsg = 'Ошибка при удалении записи. Возможно, вы пытались удалить несуществующую запись.' + + self.propertyLatestName = self.db.getProperty(self.userName, 'latestName') + if self.propertyLatestName == None: + self.propertyLatestName = '' + self.propertyLatestPosition = self.db.getProperty(self.userName, 'latestPosition') + + if self.propertyLatestPosition == None: + self.propertyLatestPosition = '' + self.propertyLatestDepartment = self.db.getProperty(self.userName, 'latestDepartment') + + if self.propertyLatestDepartment == None: + self.propertyLatestDepartment = '' + self.propertyLatestChief = self.db.getProperty(self.userName, 'latestChief') + + if self.propertyLatestChief == None: + self.propertyLatestChief = '' + + def _getWeekDay(self, date): + days = {0: 'понедельник', + 1: 'вторник', + 2: 'среда', + 3: 'четверг', + 4: 'пятница', + 5: 'суббота', + 6: 'воскресенье'} + return(days[date.weekday()]) + + def _replaceTags(self, str): + str = str.replace('<', '<') + str = str.replace('>', '>') + return str + + def header(self): + output = '\n'\ + '\n'\ + '\n'\ + ' \n'\ + ' Журнал командировок\n'\ + '\n'\ + '\n' + output += '
\n' + output += '

Все журналы Сегодня Завтра

\n' % (self.tomorrow.day, self.tomorrow.month, self.tomorrow.year) + output += '

Журнал командировок

\n' + output += '
\n' + if self.errStatus: + output += ' \n' + output += ' \n' % self.errMsg + output += '
%s
\n' + return(output) + + def headerPrint(self): + output = '\n'\ + '\n'\ + '\n'\ + ' \n'\ + ' Журнал командировок\n'\ + '\n'\ + '\n'\ + ' \n' + output += '

Журнал командировок

\n' + return(output) + + def journalForDay(self): + records = self.db.journalGetRecords(self.journalDate) + output = ' \n' + output += ' \n' + output += ' \n' + output += '
\n' + output += ' \n' % (self.journalDate.day, self.journalDate.month, self.journalDate.year) + output += ' \n' + output += ' версия для печати\n' % (self.journalDate.day, self.journalDate.month, self.journalDate.year) + output += '

\n' + output += '

Дата:

\n' + output += '
\n' % self.appUrl + output += ' \n' + output += ' \n' + if self.previousDayError == False: + output += ' \n' % (self.appUrl, self.previousDay.day, self.previousDay.month, self.previousDay.year) + else: + output += ' \n' + output += ' \n' + if self.nextDayError == False: + output += ' \n' % (self.appUrl, self.nextDay.day, self.nextDay.month, self.nextDay.year) + else: + output += ' \n' + output += ' \n' + output += '
\n' + output += ' .\n' % str(self.journalDate.day).zfill(2) + output += ' .\n' % str(self.journalDate.month).zfill(2) + output += ' \n' % self.journalDate.year + output += '
\n' + output += ' %s' % self._getWeekDay(self.journalDate) + output += '

\n' + output += '
\n' + if len(records) == 0: + output += '

Записи отсутствуют.

' + else: + output += ' \n'\ + ' \n'\ + ' \n'\ + ' \n'\ + ' \n'\ + ' \n'\ + ' \n'\ + ' \n'\ + ' \n'\ + ' \n'\ + ' \n' + for i in xrange(len(records)): + if i % 2 == 1: + bgcolor = ' bgcolor = "#BFD0E0"' + else: + bgcolor = '' + output += ' \n' % bgcolor + if self.db.journalCheckDeletePermissions(self.userName, records[i].key): + deleteField = '' + else: + deleteField = '' + for field in self._replaceTags(records[i].name), self._replaceTags(records[i].position), self._replaceTags(records[i].department), str(records[i].startTime.hour) + ':' + str(records[i].startTime.minute).zfill(2), str(records[i].endTime.hour) + ':' + str(records[i].endTime.minute).zfill(2), self._replaceTags(records[i].description), self._replaceTags(records[i].chief), deleteField: + output += ' \n' % field + output += ' \n' + output += '
Фамилия И.О.ДолжностьОтделВремя началаВремя окончанияЦель и место встречиРуководительУдалить
%s
\n' + return(output) + + def journalForDayPrint(self): + records = self.db.journalGetRecords(self.journalDate) + output = '

Дата: %s.%s.%s (%s)

\n' % (str(self.journalDate.day).zfill(2), str(self.journalDate.month).zfill(2), self.journalDate.year, self._getWeekDay(self.journalDate)) + output += '

Отчёт сгенерирован: %s.%s.%s %s:%s

\n' % (str(self.now.day).zfill(2), str(self.now.month).zfill(2), self.now.year, self.now.hour, str(self.now.minute).zfill(2)) + if len(records) == 0: + output += '

Записи отсутствуют.

\n' + else: + output += ' \n'\ + ' \n'\ + ' \n'\ + ' \n'\ + ' \n'\ + ' \n'\ + ' \n'\ + ' \n'\ + ' \n'\ + ' \n' + for i in xrange(len(records)): + output += ' \n' + for field in self._replaceTags(records[i].name), self._replaceTags(records[i].position), self._replaceTags(records[i].department), str(records[i].startTime.hour) + ':' + str(records[i].startTime.minute).zfill(2), str(records[i].endTime.hour) + ':' + str(records[i].endTime.minute).zfill(2), self._replaceTags(records[i].description), self._replaceTags(records[i].chief): + output += ' \n' % field + output += ' \n' + output += '
Фамилия И.О.ДолжностьОтделВремя началаВремя окончанияЦель и место встречиРуководитель
%s
\n' + return(output) + + def addRecord(self): + output = '

Добавить запись:

\n'\ + '
\n'\ + ' \n'\ + ' \n'\ + ' \n'\ + ' \n'\ + ' \n'\ + ' \n'\ + ' \n'\ + ' \n'\ + ' \n'\ + ' \n'\ + ' \n'\ + ' \n'\ + ' \n'\ + ' \n'\ + ' \n'\ + ' \n'\ + ' \n'\ + ' \n'\ + ' \n'\ + '
Фамилия И.О.ДолжностьОтделВремя началаВремя окончанияЦель и место встречиРуководитель
\n'\ + ' \n'\ + ' \n'\ + ' \n'\ + ' \n'\ + ' \n'\ + ' \n'\ + ' \n'\ + ' \n'\ + ' \n'\ + '
Часы:
Минуты:
\n'\ + '
\n'\ + ' \n'\ + ' \n'\ + ' \n'\ + ' \n'\ + ' \n'\ + ' \n'\ + ' \n'\ + ' \n'\ + ' \n'\ + '
Часы:
Минуты:
\n'\ + '
\n'\ + '

- обязательные поля

\n'\ + '

\n'\ + '
\n' + + return(output) + + def allDays(self): + allDays = self.db.journalListDays() + output = '

Все журналы:

\n' + output += '

' + if len(allDays) == 0: + output += '

Записи отсутствуют.

\n' + else: + output += ' \n' + for i in xrange(len(allDays)): + output += ' \n' % (allDays[i].day, allDays[i].month, allDays[i].year, str(allDays[i].day).zfill(2), str(allDays[i].month).zfill(2), allDays[i].year, self._getWeekDay(allDays[i])) + output += '
%s.%s.%s%s
\n' + output += '

\n' + return(output) + + def footer(self): + output = '

© 2010 Сергей Морозов, ОАО «Промышленно - строительное товарищество»

\n' + output += '\n' + return(output) + + def footerPrint(self): + output = '

\n'\ + '

\n'\ + ' \n'\ + '
\n'\ + '

\n' + output += '\n' + return(output) diff --git a/index.py b/index.py new file mode 100644 index 0000000..33a6d53 --- /dev/null +++ b/index.py @@ -0,0 +1,28 @@ +''' +Created on 29.11.2010 + +@author: morozov +''' +import os, sys, cgitb +serverdir = os.path.dirname(__file__) +sys.path.append(serverdir + os.sep + 'include') +import functions +import database +import webInterface +cgitb.enable() +config = functions.readConfig() + +def application(environ, start_response): + db = database.dbOperations(dbname = config.mysql_database, user = config.mysql_user, password = config.mysql_password, host = config.mysql_server, port = int(config.mysql_port)) + pageParts = webInterface.pageParts(environ, db) + output = pageParts.header() + output += pageParts.journalForDay() + output += pageParts.addRecord() + output += pageParts.footer() + db.close() + + status = '200 OK' + response_headers = [('Content-type', 'text/html'), + ('Content-Length', str(len(output)))] + start_response(status, response_headers) + return([output]) diff --git a/print.py b/print.py new file mode 100644 index 0000000..f6a14a1 --- /dev/null +++ b/print.py @@ -0,0 +1,28 @@ +''' +Created on 20.12.2010 + +@author: morozov +''' + +import os, sys, cgitb +serverdir = os.path.dirname(__file__) +sys.path.append(serverdir + os.sep + 'include') +import functions +import database +import webInterface +cgitb.enable() +config = functions.readConfig() + +def application(environ, start_response): + db = database.dbOperations(dbname = config.mysql_database, user = config.mysql_user, password = config.mysql_password, host = config.mysql_server, port = int(config.mysql_port)) + pageParts = webInterface.pageParts(environ, db) + output = pageParts.headerPrint() + output += pageParts.journalForDayPrint() + output += pageParts.footerPrint() + db.close() + + status = '200 OK' + response_headers = [('Content-type', 'text/html'), + ('Content-Length', str(len(output)))] + start_response(status, response_headers) + return([output]) diff --git a/tools/.htaccess b/tools/.htaccess new file mode 100644 index 0000000..cb24fd7 --- /dev/null +++ b/tools/.htaccess @@ -0,0 +1,2 @@ +Order allow,deny +Deny from all diff --git a/tools/dbinit.py b/tools/dbinit.py new file mode 100755 index 0000000..b305ce6 --- /dev/null +++ b/tools/dbinit.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python +''' +Created on 15.09.2010 + +@author: Sergey Morozov +''' + +import MySQLdb, os, sys +toolsdir = os.path.dirname(__file__) +if toolsdir == '': + toolsdir = '.' +serverdir = toolsdir + os.sep + '..' +sys.path.append(serverdir + os.sep + 'include') +import functions +config = functions.readConfig() + +if __name__ == '__main__': + db = MySQLdb.connect( + host = config.mysql_server, + user = config.mysql_user, + passwd = config.mysql_password, + db = config.mysql_database, + port = int(config.mysql_port) + ) + cursor = db.cursor() + q = "CREATE TABLE IF NOT EXISTS `journal` ("\ + "`key` bigint(20) NOT NULL AUTO_INCREMENT,"\ + "`name` varchar(128) NOT NULL,"\ + "`position` varchar(128) NOT NULL,"\ + "`department` varchar(128) NOT NULL,"\ + "`date` date NOT NULL,"\ + "`start_time` time NOT NULL,"\ + "`end_time` time NOT NULL,"\ + "`description` text NOT NULL,"\ + "`chief` varchar(128) DEFAULT NULL,"\ + "`username` varchar(128) NOT NULL,"\ + "PRIMARY KEY (`key`)"\ + ") ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1" + cursor.execute(q) + db.commit() + q = "CREATE TABLE IF NOT EXISTS `user_settings` ("\ + "`key` bigint(20) NOT NULL AUTO_INCREMENT,"\ + "`username` varchar(128) NOT NULL,"\ + "`setting` varchar(128) NOT NULL,"\ + "`value` text,"\ + "PRIMARY KEY (`key`)"\ + ") ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1" + cursor.execute(q) + db.commit() + cursor.close() + db.close() diff --git a/tools/shell.py b/tools/shell.py new file mode 100755 index 0000000..c87c77e --- /dev/null +++ b/tools/shell.py @@ -0,0 +1,23 @@ +#!/usr/bin/python -i +''' +Created on 16.12.2010 + +@author: morozov +''' + +if __name__ == '__main__': + import os, sys, datetime + toolsdir = os.path.dirname(__file__) + if toolsdir == '': + toolsdir = '.' + serverdir = toolsdir + os.sep + '..' + sys.path.append(serverdir + os.sep + 'include') + import functions + import database + config = functions.readConfig() + try: + db = database.dbOperations(dbname = config.mysql_database, user = config.mysql_user, password = config.mysql_password, host = config.mysql_server, port = int(config.mysql_port)) + except: + print('Error!') + else: + print('Created instance (named \'db\') of \'dbOperations\' class.') diff --git a/view-all.py b/view-all.py new file mode 100644 index 0000000..96db43b --- /dev/null +++ b/view-all.py @@ -0,0 +1,28 @@ +''' +Created on 20.12.2010 + +@author: morozov +''' +import os, sys, cgitb, datetime +from wsgiref.util import application_uri +serverdir = os.path.dirname(__file__) +sys.path.append(serverdir + os.sep + 'include') +import functions +import database +import webInterface +cgitb.enable() +config = functions.readConfig() + +def application(environ, start_response): + db = database.dbOperations(dbname = config.mysql_database, user = config.mysql_user, password = config.mysql_password, host = config.mysql_server, port = int(config.mysql_port)) + pageParts = webInterface.pageParts(environ, db) + output = pageParts.header() + output += pageParts.allDays() + output += pageParts.footer() + db.close() + + status = '200 OK' + response_headers = [('Content-type', 'text/html'), + ('Content-Length', str(len(output)))] + start_response(status, response_headers) + return([output])