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`
zB?Zr_3oD(p*RHE>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 += ' %s |
\n' % self.errMsg
+ output += '
\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' % (self.journalDate.day, self.journalDate.month, self.journalDate.year)
+ output += ' | \n'
+ output += ' \n'
+ output += ' версия для печати\n' % (self.journalDate.day, self.journalDate.month, self.journalDate.year)
+ output += ' | \n'
+ output += '
\n'
+ 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 += ' %s | \n' % field
+ output += '
\n'
+ output += '
\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 += ' %s | \n' % field
+ output += '
\n'
+ output += '
\n'
+ return(output)
+
+ def addRecord(self):
+ output = ' Добавить запись:
\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 += ' %s.%s.%s | %s |
\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 += '
\n'
+ output += '
\n'
+ return(output)
+
+ def footer(self):
+ output = '
© 2010 Сергей Морозов, ОАО «Промышленно - строительное товарищество»
\n'
+ output += '\n'
+ return(output)
+
+ def footerPrint(self):
+ output = ' \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])