From 3e4863d0c69c38ddbf7b6ab1bae02169812d734d Mon Sep 17 00:00:00 2001 From: kerem Date: Sun, 22 Oct 2023 22:08:22 +0200 Subject: [PATCH] Project view is nearly done --- webinterface/$ | 269 ------------------ webinterface/__pycache__/test.cpython-311.pyc | Bin 0 -> 576 bytes .../2029240f6d1128be89ddc32729463129 | Bin 0 -> 9 bytes .../85d4d4491cdf35f65aeeb65c2150079b | Bin 0 -> 33 bytes .../c955664f3c1afea310d3fa9de93b2054 | Bin 0 -> 44 bytes .../f397c9806198dce1bc23d1226063df58 | Bin 0 -> 252 bytes webinterface/instance/site.db | Bin 0 -> 258048 bytes webinterface/minibase/__init__.py | 11 +- .../__pycache__/__init__.cpython-311.pyc | Bin 2489 -> 2646 bytes .../admin/__pycache__/utils.cpython-311.pyc | Bin 576 -> 558 bytes webinterface/minibase/admin/utils.py | 2 +- .../company/__pycache__/forms.cpython-311.pyc | Bin 3014 -> 3006 bytes webinterface/minibase/company/forms.py | 10 +- .../minibase/database/.~lock.person.csv# | 1 + .../__pycache__/models.cpython-311.pyc | Bin 38459 -> 39954 bytes .../__pycache__/utils.cpython-311.pyc | Bin 14151 -> 18394 bytes webinterface/minibase/database/models.py | 38 ++- webinterface/minibase/database/person.csv | 6 +- webinterface/minibase/database/utils.py | 126 +++++++- .../person/__pycache__/forms.cpython-311.pyc | Bin 3333 -> 3333 bytes webinterface/minibase/person/forms.py | 8 +- .../project/__pycache__/forms.cpython-311.pyc | Bin 0 -> 4669 bytes .../__pycache__/routes.cpython-311.pyc | Bin 0 -> 6920 bytes webinterface/minibase/project/forms.py | 48 ++++ webinterface/minibase/project/routes.py | 114 ++++++-- webinterface/minibase/site.db | Bin 290816 -> 290816 bytes webinterface/minibase/site.db.bak | Bin 0 -> 290816 bytes .../minibase/static/pics/default_project.jpg | Bin 0 -> 10994 bytes webinterface/minibase/templates/layout.html | 15 +- .../templates/project/select_company.html | 30 ++ .../templates/project/select_project.html | 31 ++ .../templates/project/show_project.html | 209 ++++++++++++++ webinterface/prepare.py | 30 +- webinterface/python_requirements | 20 ++ webinterface/test.py | 7 + 35 files changed, 639 insertions(+), 336 deletions(-) delete mode 100644 webinterface/$ create mode 100644 webinterface/__pycache__/test.cpython-311.pyc create mode 100644 webinterface/flask_session/2029240f6d1128be89ddc32729463129 create mode 100644 webinterface/flask_session/85d4d4491cdf35f65aeeb65c2150079b create mode 100644 webinterface/flask_session/c955664f3c1afea310d3fa9de93b2054 create mode 100644 webinterface/flask_session/f397c9806198dce1bc23d1226063df58 create mode 100644 webinterface/instance/site.db create mode 100644 webinterface/minibase/database/.~lock.person.csv# create mode 100644 webinterface/minibase/project/__pycache__/forms.cpython-311.pyc create mode 100644 webinterface/minibase/project/__pycache__/routes.cpython-311.pyc create mode 100644 webinterface/minibase/site.db.bak create mode 100644 webinterface/minibase/static/pics/default_project.jpg create mode 100644 webinterface/minibase/templates/project/select_company.html create mode 100644 webinterface/minibase/templates/project/select_project.html create mode 100644 webinterface/minibase/templates/project/show_project.html create mode 100644 webinterface/python_requirements create mode 100644 webinterface/test.py diff --git a/webinterface/$ b/webinterface/$ deleted file mode 100644 index 834e0dc8..00000000 --- a/webinterface/$ +++ /dev/null @@ -1,269 +0,0 @@ -from minibase.database.models import Company, Company_relation, Company_legal_entity -from minibase.database.models import Industry, Countries -from minibase.database.models import Person, Person_role, Person_competence -from minibase.database.models import Project, Project_element -from minibase import db -from numpy import genfromtxt - - -# Gets the id of company from the formated output defined at models.py for the Company Model -# The argument formatedCompanySelection is formated by SQLAlchemy in models.py files -# Please look there before changing anything here. -def getCompanyId(formatedCompanySelection): - text = formatedCompanySelection.split(",") - return text[2] # Corresponds to the ID of the Company - - -# Gets the id of Person's role -def getPersonRoleId(nameForId): - selection = Person_role.query.filter_by(name=nameForId).first() - return selection.id - - -# Gets the id of Person's competence -def getPersonCompetenceId(nameForId): - selection = Person_competence.query.filter_by(name=nameForId).first() - return selection.id - - -# Gets the country of the company based on it's id -def getCompanyCountry(companyId): - selection = Company.query.filter_by(id=companyId).first() - return selection.country_bill - - -# Gets the state of the company based on it's id -def getCompanyState(companyId): - selection = Company.query.filter_by(id=companyId).first() - return selection.street_bill - - -# Gets the city of the company based on it's id -def getCompanyCity(companyId): - selection = Company.query.filter_by(id=companyId).first() - return selection.city_bill - - -# Gets the Postal Code of the company based on it's id -def getCompanyPostCode(companyId): - selection = Company.query.filter_by(id=companyId).first() - return selection.post_code_bill - - -# Gets the Name of the street of the company based on it's id -def getCompanyStreetName(companyId): - selection = Company.query.filter_by(id=companyId).first() - return selection.street_bill - - -# Gets the Number of the street of the company based on it's id -def getCompanyStreetNo(companyId): - selection = Company.query.filter_by(id=companyId).first() - return selection.street_no_bill - - -# Returns the query of all awailable companie names on the table named Company -# Note that the formating is done during the SQLAlchemy Table declaration. -def person_role_choices(): - choices = Person_role.query.all() - return choices - - -# Returns the query of all awailable companie names on the table named Company -# Note that the formating is done during the SQLAlchemy Table declaration. -def person_competence_choices(): - choices = Person_competence.query.all() - return choices - - -# Returns the query of all awailable companie names on the table named Company -# Note that the formating is done during the SQLAlchemy Table declaration. -def company_choices(): - choices = Company.query.all() - return choices - - -# Retunrs the qurry of all awailable industrie names on the table named Industry -# Note that the formating is done during the SQLAlchemy Table declaration. -def company_industry_choices(): - choices = Industry.query.all() - return choices - - -# Retunrs the query of all awailable legal entity names on the table named Company_legal_entity -# Note that the formating is done during the SQLAlchemy Table declaration. -def company_legal_entity_choices(): - choices = Company_legal_entity.query.all() - return choices - - -# Retunrs the query of all awailable Relation names on the table named Company_relation -# Note that the formating is done during the SQLAlchemy Table declaration. -def company_relation_choices(): - choices = Company_relation.query.all() - return choices - - -# The Company Model has Industry Column as a foreign key and it requires the Industry's ID -# And not the name. so this function returns the right ID of the name shown at the -# Register Company Form -def getIndustryId(nameForId): - selection = Industry.query.filter_by(name=nameForId).first() # Gets the id of Role - return selection.id - - -# The Company Model has Relation Column as a foreign key and it requires the Industry's ID -# And not the name. so this function returns the right ID of the name shown at the -# Register Company Form -def getRelationId(nameForId): - selection = Company_relation.query.filter_by(name=nameForId).first() # Gets the id of Role - return selection.id - - -# The Company Model has Legal Entity Column as a foreign key and it requires the Industry's ID -# And not the name. so this function returns the right ID of the name shown at the -# Register Company Form -def getLegalEntityId(nameForId): - selection = Company_legal_entity.query.filter_by(name=nameForId).first() # Gets the id of Role - return selection.id - - -# Retunrs the query of all awailable Country names on the table named Countries -# Note that the formating is done during the SQLAlchemy Table declaration. -# Important note This table is ImporteD externally from a modifier SQL version of -# Github : https://github.com/dr5hn/countries-states-cities-database -def country_choices(): - choices = Countries.query.all() - return choices - -################################################################################################### -# CSV manipulation -################################################################################################### - -def openCsv(filename): - data = genfromtxt(filename, - delimiter=',', - skip_header=1, - dtype=None, - encoding='UTF-8') - return data.tolist() - - -def db_add_name_and_description(csv, table): - try: - csv_list = openCsv(csv) - for i in csv_list: - record = table(**{ - 'name': i[0], - 'description': i[1]}) - db.session.add(record) # Add all the records - db.session.commit() # Attempt to commit all the records - except: - db.session.rollback() # Rollback the changes on error - print("Error Ocured during <> upload to DB") - - -def db_add_company(csv): - try: - csv_list = openCsv(csv) - for i in csv_list: - record = Company(**{ - 'name': i[0], - 'legal_entity_id': i[1], - 'relation_id': i[2], - 'industry_id': i[3], - 'status_id': i[4], - 'website': i[5], - 'street_bill': i[6], - 'street_no_bill': i[7], - 'city_bill': i[8], - 'post_code_bill': i[9], - 'state_bill': i[10], - 'country_bill': i[11], - 'street_ship': i[12], - 'street_no_ship': i[13], - 'city_ship': i[14], - 'post_code_ship': i[15], - 'state_ship': i[16], - 'country_ship': i[17]}) - db.session.add(record) # Add all the records - db.session.commit() # Attempt to commit all the records - except Exception as error: - db.session.rollback() # Rollback the changes on error - print("Error Ocured during <> upload to DB") - print(error) - - -def db_add_person(csv): - try: - csv_list = openCsv(csv) - print(csv_list) - for i in csv_list: - record = Person(**{ - 'name': i[0], - 'last_name': i[1], - 'company_id': i[2], - 'role_id': i[3], - 'competence_id': i[4], - 'mail_prof': i[5], - 'mail_priv': i[6], - 'tel_prof_mobile': i[7], - 'street_name': i[8], - 'street_no': i[9], - 'city': i[10], - 'post_code': i[11], - 'state': i[12], - 'country': i[13] - }) - db.session.add(record) # Add all the records - db.session.commit() # Attempt to commit all the records - except Exception as error: - db.session.rollback() # Rollback the changes on error - print("Error Ocured during <> upload to DB") - print(error) - - -def db_add_project(csv): - try: - csv_list = openCsv(csv) - print(csv_list) - for i in csv_list: - record = Project(**{ - 'name': i[0], - 'description': i[1], - 'company_id': i[2], - 'status_id': i[3], - 'industry_id': i[4], - 'owner_id': i[5], - 'qte_prototype': i[6], - 'qte_start': i[7], - 'qte_production': i[8], - }) - db.session.add(record) # Add all the records - db.session.commit() # Attempt to commit all the records - except Exception as error: - db.session.rollback() # Rollback the changes on error - print(csv) - print("Error Ocured during <> upload to DB") - print(error) - -def db_add_project_element(csv): - try: - csv_list = openCsv(csv) - print(csv_list) - for i in csv_list: - record = Project_element(**{ - 'name': i[0], - 'description': i[1], - 'qte_per_project': i[2], - 'project_id': i[3], - 'owner_id': i[4], - 'status_id': i[5], - }) - db.session.add(record) # Add all the records - db.session.commit() # Attempt to commit all the records - except Exception as error: - db.session.rollback() # Rollback the changes on error - print(csv) - print("Error Ocured during <> upload to DB") - print(error) diff --git a/webinterface/__pycache__/test.cpython-311.pyc b/webinterface/__pycache__/test.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..58451a916d9f0b2c2c8975763917e527597b3bbe GIT binary patch literal 576 zcmZ`zO;5r=5S`tHQb9t95%>u*qE-{U9I9(oDhc!cSj5kh8gko*@j(2^~&&4PPAl>K2aQJPbw fIb<_ncePP%0`)1>-=XmajR~}-&`R=%>iCTx!BCc& literal 0 HcmV?d00001 diff --git a/webinterface/flask_session/2029240f6d1128be89ddc32729463129 b/webinterface/flask_session/2029240f6d1128be89ddc32729463129 new file mode 100644 index 0000000000000000000000000000000000000000..ffb2cd9bfd75610267f6ba499787709ee5ac010d GIT binary patch literal 9 QcmZQzU|?uq^=8%s00XiC0ssI2 literal 0 HcmV?d00001 diff --git a/webinterface/flask_session/85d4d4491cdf35f65aeeb65c2150079b b/webinterface/flask_session/85d4d4491cdf35f65aeeb65c2150079b new file mode 100644 index 0000000000000000000000000000000000000000..9ae1a868856612f2aa223dd50bfaa6cac142ee38 GIT binary patch literal 33 kcmWf+5|P@#I#q}P0&1u9aK#s-7Ud@9rRJ4P=_u9%0GxCRUjP6A literal 0 HcmV?d00001 diff --git a/webinterface/flask_session/c955664f3c1afea310d3fa9de93b2054 b/webinterface/flask_session/c955664f3c1afea310d3fa9de93b2054 new file mode 100644 index 0000000000000000000000000000000000000000..e7645c848070bc466f04de2288c6ca39d79cef12 GIT binary patch literal 44 vcmWf+5|P@#I#red0&1sd^l-%&q!#5S=B4J9OzG%hi%%;`EzX$IS*iyBB)bl} literal 0 HcmV?d00001 diff --git a/webinterface/flask_session/f397c9806198dce1bc23d1226063df58 b/webinterface/flask_session/f397c9806198dce1bc23d1226063df58 new file mode 100644 index 0000000000000000000000000000000000000000..0f7de990b4a1c9499363bf4ea7cd700c0202c24d GIT binary patch literal 252 zcmXAhF-`+95Jf=*gRA|QQ8GEimV|lz|flwB-o0O4Krf_MF!11^P7QE{J_oe^+ z^kSF$ub-QL&VAo@>C@IjUTit`YulA=t?BsjZcA@_W<;j!T&Qzl2qtkm_pN>v(ufr_I*%HurXmz1{t#i{`>M`Qp5qDrx9RHP_ioy1Fsq+_PY x24VqbG71A#66Z{7m;y#-RThDv#fewX-ZK#dVo`Pws*|i90oi!;N^?Iw{{lCYOI-i} literal 0 HcmV?d00001 diff --git a/webinterface/instance/site.db b/webinterface/instance/site.db new file mode 100644 index 0000000000000000000000000000000000000000..e1f92aed6a2b15ff0943001c616992669a912e9b GIT binary patch literal 258048 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 V*}(pRjX_D{1A`(XKTZN{F#!E~pML-V delta 490 zcmca6vQwCEIWI340}xnkQcJC5o5&}@cwwS?3?uWzmJEkf-ZaJ(t`^29kreJ=22Gxq zAcdNYw^-eB5{t8e46finAIF^JjMUspAWtAAH904-D6u57EHyqUu{d?IIb$f}w#~ha z{fsO%j0+?tH!=%Pwr3V&gs?KY^$8m@`h~8pN1NpCr8DyLQm>pkSn3D+cXb}rYSPCJa zms(MxhvfCi%Q=F$#ej;6BtV4ZWEM^hEh!KaWbI0ZB6Sd36-fNzu*uC&Da}c>D>4Fd s8G*R?$>exW871`#3@GRZgZTwiG+A0AZwu&;S4c diff --git a/webinterface/minibase/admin/__pycache__/utils.cpython-311.pyc b/webinterface/minibase/admin/__pycache__/utils.cpython-311.pyc index 8d9728b63c1193a8d8ea79bea88cde360c88d19c..30cac5ad71bd77d0c8f42c76a0c7b99a12f55747 100644 GIT binary patch delta 175 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 delta 3122 zcmbW3UrbY17{GfeErqtX@~;$HTA(Nv6rF6a35v)c6*mxFbdqSf^jz?2dv87WR;fl| z3)x>6W6qM9>`$`9>3Cb#2OsvZJuESMlV!==P29_#j4$qCFI%$h`%X(+6>zbkKTf}M z&iCh>?>pz1SA{#Oc+2gsu)ycvnNE3Y`!&%g*sryX&kGh}A-1?H;huE!wmmK;Jd+-1 zmn~W*HxLJ~l9U6hNCmK(IDs|91*|1*pqGfiI^qHP$Od3NsRTBVDxjZK0|TT6*hp%D zLE;65NF8uj6Y;^nW>ODqAq~JV@dH~)0JxDf0ymK$u#JR(n@JNeLYj|QA}#EOa6z!L zP>G*Smi%L@gYaCL6IO@d_d?V3%*w_gnd+K)Sc}UC2n~a@iY=7BEcn>6t)6{uog1SK zAdJ{3E)ESK8WBN62+;)4O8`wxl&h`Hs~yx5N!gIq7%JZgLwxMIt)Tppk81$sR_H5M z&fY5vMOvOzTnUO%rKF|@wUlbmH0^*fLAG30P&(I5+d#PVv{I0oPTiogY(%G(c$`Lx z4X|ZLt!*1fTG>NKk-FEox>bBcb>%U|NUx#{`@|w|VHE8GVLQ0mWe?sh4buDyA6?IY znACJ58qEh&Xh*`KtFzIPu9?QAnIBY#v)c)j)DOD!`~oynJZ9l z+Y5q0)*fhuEFBL_wd{u9Fs_iG{WxO}KovJF9dl>NCfZ7Mgdka|x|g9)Z5 zmQA>5?3AX&WSx$HbOOFQ*2RM5zF2!D@rxMxNenHE%|DCH3;XUls}{y!t-!b8oDn;W z&F1&2Mtmzq6qTf4_0oB3`(ff6>~>@L@mOtZ>tiQ^Ew)kUkFv$!6H8RO&a{qD(Do|y z&#mFyCIVfe$o*3L0_ai>lLpK5vNTf zVhDne5i^Kc0Gzg`uzebF1`$Uj06K0?6Mmo$zu!`0zXHF%vSiFHvC@+m0j)ylh!o;H zVh)i;TtHkzTtZw%EFj(jL_~_~W0uDyI3`s%vCN8mEfMz73pY;`N5kWPb~N+@&{^y^ znsAfps6il4(xCiK+U zzktcVTQdHhJ=XneITo=OJTX0IAqOC;Xp(BD<(OesDQ>tH{Ql6O(!Nl0pHMv56J3R?rx_d!a(L=>lr8wKm7 z%Jyu5uA0)~N=j3Wq+$lW4a&q!^+2dZXlGr66Z576*KJzTWp2Z?si{OVO+9E7ACvsS z$RBq6Ax81}#NRpm3Bn%_{9>njv114^g4mD1JBs3s!*2+R=R3vInc~^XPoINS#U>sY zyxu70HpTSeuJVPTKK$tg{N?CNKpb&-H~kiV3h>oCAhjM@1wpvSz8-2|cZPZcBX=!p o{;}@i){;jqHZ#19-55S5i0uBzD0?{KVQu^Rgbj@Bqoru?KLy{>MgRZ+ diff --git a/webinterface/minibase/database/models.py b/webinterface/minibase/database/models.py index 36249d2d..a749f279 100644 --- a/webinterface/minibase/database/models.py +++ b/webinterface/minibase/database/models.py @@ -1,4 +1,4 @@ -from itsdangerous import TimedJSONWebSignatureSerializer as Serializer +from itsdangerous import URLSafeTimedSerializer as Serializer from datetime import datetime from minibase import db, login_manager from flask_login import UserMixin @@ -49,7 +49,6 @@ class Post(db.Model): def __repr__(self): return f"User('{self.title}', '{self.date_posted}')" - ################################################################################################### # ADMIN ################################################################################################### @@ -107,6 +106,7 @@ class Note_status(db.Model): last_update_date = db.Column(db.DateTime, nullable=False, default=datetime.utcnow, onupdate=datetime.utcnow) company_notes = db.relationship('Company_note', backref='company_note_status', lazy=True) person_notes = db.relationship('Person_note', backref='person_note_status', lazy=True) + project_notes = db.relationship('Project_note', backref='project_note_status', lazy=True) # returns a more information-rich, or official, string representation of an object def __repr__(self): @@ -172,8 +172,11 @@ class Person(db.Model): # One To Many relationships for a company having mutliple elements of the following indexes # Example : One company would/could have many eployees notes = db.relationship('Person_note', backref='person', lazy=True) - projects = db.relationship('Project', backref='project_responsible', lazy=True) - elements = db.relationship('Project', backref='element_responsible', lazy=True) + projects = db.relationship('Project', backref='project_responsible', lazy=True, viewonly=True) + elements = db.relationship('Project', backref='element_responsible', lazy=True, viewonly=True) + + def __repr__(self): + return f"{self.name} {' '} {self.last_name}" class Person_role(db.Model): @@ -299,7 +302,8 @@ class Company_note(db.Model): # returns a more information-rich, or official, string representation of an object def __repr__(self): - return f"{self.title}, {self.status}, {self.content}" + return f"{self.title}, {self.content}" + ################################################################################################### # Project @@ -316,8 +320,9 @@ class Project(db.Model): qte_production = db.Column(db.Integer, nullable=False) upload_date = db.Column(db.DateTime, nullable=False, default=datetime.utcnow) last_update_date = db.Column(db.DateTime, nullable=False, default=datetime.utcnow, onupdate=datetime.utcnow) + image_file = db.Column(db.String(30), nullable=False, default='default_project.jpg') - # One To Many relationships where indexes can point o mutiple companies. + # One To Many relationships where indexes can point o mutiple compani30. company_id = db.Column(db.Integer, db.ForeignKey('company.id'), nullable=False) status_id = db.Column(db.Integer, db.ForeignKey('project_status.id'), nullable=False) industry_id = db.Column(db.Integer, db.ForeignKey('industry.id'), nullable=False) @@ -326,6 +331,7 @@ class Project(db.Model): # One To Many relationships for a company having mutliple elements of the following indexes # Example : One company would/could have many eployees elements = db.relationship('Project_element', backref='project', lazy=True) + notes = db.relationship('Project_note', backref='project', lazy=True) # returns a more information-rich, or official, string representation of an object def __repr__(self): @@ -354,13 +360,29 @@ class Project_status(db.Model): upload_date = db.Column(db.DateTime, nullable=False, default=datetime.utcnow) last_update_date = db.Column(db.DateTime, nullable=False, default=datetime.utcnow, onupdate=datetime.utcnow) - projects = db.relationship('Project', backref='status', lazy=True) - elements = db.relationship('Project', backref='element_status', lazy=True) + projects = db.relationship('Project', backref='status', lazy=True, viewonly=True) + elements = db.relationship('Project', backref='element_status', lazy=True, viewonly=True) # returns a more information-rich, or official, string representation of an object def __repr__(self): return f"{self.name}" + +class Project_note(db.Model): + id = db.Column(db.Integer, primary_key=True) + priority = db.Column(db.Integer, nullable=False, default='0') + title = db.Column(db.String(100), nullable=False) + content = db.Column(db.Text, nullable=False) + date_posted = db.Column(db.DateTime, nullable=False, default=datetime.utcnow) + date_due = db.Column(db.DateTime, nullable=False, default=datetime.utcnow) + + project_id = db.Column(db.Integer, db.ForeignKey('project.id'), nullable=False) + status_id = db.Column(db.Integer, db.ForeignKey('note_status.id'), nullable=False) + + # returns a more information-rich, or official, string representation of an object + def __repr__(self): + return f"{self.title}, {self.content}" + ################################################################################################### # Product ################################################################################################### diff --git a/webinterface/minibase/database/person.csv b/webinterface/minibase/database/person.csv index 41ae2d9b..d406c4f6 100644 --- a/webinterface/minibase/database/person.csv +++ b/webinterface/minibase/database/person.csv @@ -1,3 +1,5 @@ name,last_name,company_id,role_id,competence_id,mail_prof,mail_priv,tel_prof_mobile,street_name,street_no,city,post_code,state,country -Kerem,Yollu,2,3,1,kerem.yollu_at_kynsight.com,kerem.yollu@gmail.com,41789716697,Meierackerstrasse,10,Uster,8610,Zürich,Switzerland -Stefan,Walker,1,2,2,stefan.walker_at_steinel.ch,stefan.walker@gmail.com,41789716697,Almeinderstrasse,10,Einsiedeln,8410,Schwyz,Switzerland +Kerem,Yollu,2,3,1,kerem.yollu@kynsight.com,kerem.yollu@gmail.com,41789716697,Meierackerstrasse,10,Uster,8610,Zürich,Switzerland +Stefan,Walker,1,2,2,stefan.walker@steinel.ch,stefan.walker@gmail.com,41789716697,Almeinderstrasse,10,Einsiedeln,8410,Schwyz,Switzerland +Meier,Müller,1,2,2,meier.mueller@steinel.ch,meier.mueller@steinel.ch,41789716697,Almeinderstrasse,10,Einsiedeln,8410,Schwyz,Switzerland +Suleyman,Siksok,1,2,2,suleyman.siksok@steinel.ch,suleyman.siksok@steinel.ch,41789716697,Almeinderstrasse,10,Einsiedeln,8410,Schwyz,Switzerland diff --git a/webinterface/minibase/database/utils.py b/webinterface/minibase/database/utils.py index 2f6a7285..299d8d93 100644 --- a/webinterface/minibase/database/utils.py +++ b/webinterface/minibase/database/utils.py @@ -1,10 +1,13 @@ from minibase.database.models import Company, Company_relation, Company_legal_entity from minibase.database.models import Industry, Countries from minibase.database.models import Person, Person_role, Person_competence -from minibase.database.models import Project, Project_element, Product +from minibase.database.models import Project, Project_element, Project_status, Project_note +from minibase.database.models import Product from minibase import db from numpy import genfromtxt +selectedCompany=0 +selectedProject=0 # Gets the id of company from the formated output defined at models.py for the Company Model # The argument formatedCompanySelection is formated by SQLAlchemy in models.py files @@ -26,6 +29,12 @@ def getPersonCompetenceId(nameForId): return selection.id +# Gets the name based on Person's id +def getPersonName(personId): + selection = Person.query.filter_by(id=personId).first() + return selection + + # Gets the country of the company based on it's id def getCompanyCountry(companyId): selection = Company.query.filter_by(id=companyId).first() @@ -62,7 +71,108 @@ def getCompanyStreetNo(companyId): return selection.street_no_bill -# Returns the query of all awailable companie names on the table named Company +# Gets the names the all the companies +def getCompanyNames(): + selection = Company.query.order_by(Company.name.asc()) + return selection + + +# Gets the Name of the street of the company based on it's id +def getCompanyName(companyId): + selection = Company.query.filter_by(id=companyId).first() + return selection.name + +#################################################################################################### +# Gets the Project class of based on it's id +def getProject(projectId): + selection = Project.query.filter_by(id=projectId).first() + return selection + +# Gets the names the all the projects +def getProjectNames(): + selection = Project.query.order_by(Project.name.asc()) + return selection + +# Gets the awailable Statuses of all the projects +def getProjectStatuses(): + selection = Project_status.query.order_by(Project_status.name.asc()) + return selection + +# Gets the Name of the street of the company based on it's id +def getProjectName(projectId): + selection = Project.query.filter_by(id=projectId).first() + return selection.name + + +# Defines the selected company for the current request. This is important to fill so that some +# Templates knows if they have to show something and warns the user if no compani was selected +def setSelectedCompany(company_id): + global selectedCompany + selectedCompany = int(company_id) + + +# Returns the Selected company +def getSelectedCompany(): + global selectedCompany + return selectedCompany + + +# Get the list of projects for the selected Company and if no company was selected +# Prints an error that will be put in the selection form. +def getProjectOfSelectedCompany(): + global selectedCompany + if selectedCompany: + selection = Project.query.filter_by(company_id=selectedCompany) + return selection + return ["No company is selected"] + +# Get the list of projects for the selected Company and if no company was selected +# Prints an error that will be put in the selection form. +def getEmployeesOfSelectedCompany(): + global selectedCompany + if selectedCompany: + selection = Person.query.filter_by(company_id=selectedCompany) + return selection + return ["No company is selected"] + + +# Defines the selected project for the current request. This is important to fill so that some +# Templates knows if they have to show something and warns the user if no compani was selected +def setSelectedProject(project_id): + global selectedProject + selectedProject = int(project_id) + + +# Returns the Selected project +def getSelectedProject(): + return selectedProject + + +def getSelectedProjectOwner(): + global selectedProject + if selectedProject: + selection = Project.query.filter_by(id=selectedProject).first() + return getPersonName(selection.project_responsible.id) + return ["No Project is selected"] + + +def getSelectedProjectNotes(): + global selectedProject + if selectedProject: + selection = Project_note.query.filter_by(project_id=selectedProject) + return selection + return ["No Project is selected"] + + +# Get the project id based on the project's name and compan's id +# As they can be project's that have the same name but corresponds to different companies. +def getProjectId(companyId, projectName): + global selectedCompany + selection = Project.query.filter_by(company_id=companyId, name=projectName).first() + return selection.id + + +# Returns the query of all awailable companie names on the table named Project # Note that the formating is done during the SQLAlchemy Table declaration. def person_role_choices(): choices = Person_role.query.all() @@ -76,16 +186,9 @@ def person_competence_choices(): return choices -# Returns the query of all awailable companie names on the table named Company -# Note that the formating is done during the SQLAlchemy Table declaration. -def company_choices(): - choices = Company.query.all() - return choices - - # Retunrs the qurry of all awailable industrie names on the table named Industry # Note that the formating is done during the SQLAlchemy Table declaration. -def company_industry_choices(): +def getIndustryNames(): choices = Industry.query.all() return choices @@ -132,10 +235,11 @@ def getLegalEntityId(nameForId): # Note that the formating is done during the SQLAlchemy Table declaration. # Important note This table is ImporteD externally from a modifier SQL version of # Github : https://github.com/dr5hn/countries-states-cities-database -def country_choices(): +def getCountryNames(): choices = Countries.query.all() return choices + ################################################################################################### # CSV manipulation ################################################################################################### diff --git a/webinterface/minibase/person/__pycache__/forms.cpython-311.pyc b/webinterface/minibase/person/__pycache__/forms.cpython-311.pyc index b183639d4470ec3dd8396ef2981335fd3e234548..ec27b3339671b3dec725f18d9ef0092f5a7ec802 100644 GIT binary patch delta 48 zcmZpbYL((%&dbZi00jG#4L5RM;t)$o3N6XZDZa&@o?7CZpIeZaSLv6SyZJMR5DNfO CQV)s% delta 48 zcmZpbYL((%&dbZi00hkI)HZTo;t+F53N6XZDZa&@oS$2em{%E}oROcIy!kVS5DNfE Coex+5 diff --git a/webinterface/minibase/person/forms.py b/webinterface/minibase/person/forms.py index 0c51c43c..83eb118c 100644 --- a/webinterface/minibase/person/forms.py +++ b/webinterface/minibase/person/forms.py @@ -2,7 +2,7 @@ from flask_wtf import FlaskForm from wtforms import StringField, SubmitField, SelectField, DateField from wtforms.validators import DataRequired, Length, ValidationError, Email, Optional from minibase.database.models import Person -import minibase.database.utils as DbUtils +import minibase.database.utils as dbUtils # Defines the form class to be used for the user registretion @@ -17,9 +17,9 @@ class personForm(FlaskForm): tel_prof_mobile = StringField('Tel Professional Mob', validators=[Optional()]) tel_priv_fix = StringField('Tel Private Fix', validators=[Optional()]) tel_priv_mobile = StringField('Tel Private Mob', validators=[Optional()]) - company_id = SelectField('Company', choices=DbUtils.company_choices, validators=[DataRequired()]) - competence_id = SelectField('Competence', choices=DbUtils.person_competence_choices, validators=[DataRequired()]) - role_id = SelectField('Role', choices=DbUtils.person_role_choices, validators=[DataRequired()]) + company_id = SelectField('Company', choices=dbUtils.getCompanyNames, validators=[DataRequired()]) + competence_id = SelectField('Competence', choices=dbUtils.person_competence_choices, validators=[DataRequired()]) + role_id = SelectField('Role', choices=dbUtils.person_role_choices, validators=[DataRequired()]) submit = SubmitField('Register Person') # Queries to be made in order to validate the form : If person with this name exitst within the same company diff --git a/webinterface/minibase/project/__pycache__/forms.cpython-311.pyc b/webinterface/minibase/project/__pycache__/forms.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..07b093f3b1f76a8bf7890ce37d494ddf7cd549fd GIT binary patch literal 4669 zcmc&&&2tmU6(4ORrw*Ch~Ou@laaWGXJyj6Q}s&eS5nuBUCNmWjq!WMh-DeujUEK4@AIAuI~ zbieoOH{JcZf3KUr@q8x-&wu{;DarXb?%!CcKOI)#od$*PIgt}>1+HjI+iY027wknx z+EH|-oyCrHN70pb72RpKVRIBbMQ_?$>`ZqSeQBSea~AwXKFt?}v|!Xb3V~uUXSZ?1 zu5`%8*||whbp3@B-Ng39!Ew*vXFln$Ve^2^yU!LeY@J~9?Xz_oHb2<-eYPI4<2n}= z-ry&qHr+c>$jbL7%Cs2m(0$hz=ZlguA(4Uz6;dEMtKuEcD#XST@YTe-P*T;-!0AFWQ{A3a+4`hN|h6^lj~Erk(A8iYPBNA?D7NF+)Y!T_%$6{HOWS}Xg{_*g2I@T0W1yHg#ZP49K?Z>KErZl zc-7o}Eq9;IQzpo&AZvnbO*-q3tNdw=KfQO>(Rb6VV_@-lcf-Da^T1YcHg6cvbclA* z@!a_Y@Xz39K6(4|j%H2T1z6aC@Acto!-u&UQMU90Hg4Sl;l9-VgUH7=F?F;n)D6f*HxB6B8|)+y zr~_yUME1{5Z4}4*W*CTgrwiapSy>`OR~NG-MN*b_f|jZRxn&4*&ra8MB})~o)`2E3CFmZhBreJdU0Uv$sX($K$mt7^nue}O zIc1R&-Ep^)*BzBoemPhlZk_j2(W9-@f&0%O28ss_-HBh)eIk)_RH|V2s2lbE`wFQK zmQc)ix*xx8>4@$DfH6efi+Zydsw*1<(*>)UHTnj3(O&FIAG!_#izTdaVsvDB8f|_Q zJObPmbFl9xv5ydo0%I!w6$02Gv6`=E<%`wtHikEbU&LOZMuj z(kwgkE%VK(zB$b|R~@f~j;)?rD{c;K4!jzCJ-FSo-NUA5*v;E4kx>&FEslUguYP1O2-wKl*` ze6c;SJ@EIze+;tA-?IKWwSP|QpJUFRTKC}U96Nq`v#?osReD`w7m}5Z zYcHDyj;uUf`+WU@7N2A@S$Nf%oHmnV(;^EHH9)igfo=-DD-!EFy?Jl*-u5|mZFW1R zj?QVLbL>Kz2{%>YrY79n%@U_nepus&_ht!<+re4l1TcQ<5oX1aX1Si zx4Xsmvw^$KY=GSE`+#h~i|u6tWO$$0UN%66=f(E20rIj>#9VXuoOKy~u_uRPLx2j4 z*prAD6ua7BeKSvlT3EkV3v6STrSDde1XtYXdXuK2?#h)*O`7C_>RWV5C@^VEh468P<0luLW8RD_??RO{cjqk zzrm))sm|<=Z1sl{xl->B@-jV#!k}Y*4;@zs{Vf{KgV1@Cy6b%VIU07El#XE4iQ=H6 z;3yhUd<;MNyJi;sP+By(V`F4v<=KYIH3`C}Fv zW&A~zzo_vSs}n5*%+6nCp@bSrXraWRY#TYYnqY%Xq!&r4k(3rmRg-P7?OJ@}(Z-_} zk6%7!pG~mfq#B&mf|EeDk)hQo_KVN9rnaVjNd1^%W7k<^T8&I=k!f&z2-gBXu6frV zu0P!TYU|wQs2cxTi+{~x-!NfH6{a*{YL^|ODt}VrPwr($j7PLr_b%X_IP*YRpm=!E z-B7}NlNn88@!-NR@;AjauZJu|tZ^@Fq<#wjy};?huG1JEDjEw#@2%h6VzAJ%c!`TG z8n;4Ey{>l{3gaST-rVrCZzN%34Yk}ec042It#g#700(OeE*l`xnc4T_O?Gz$g#hMq9rx4j{GH!GK1&G+W?*IS* literal 0 HcmV?d00001 diff --git a/webinterface/minibase/project/__pycache__/routes.cpython-311.pyc b/webinterface/minibase/project/__pycache__/routes.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..66efdbe445193bbf75e9874cb7e5511a1b910706 GIT binary patch literal 6920 zcmcgwO>7&-6<+>nNpUIC`mtr}hZIRsqJKmylAs^UauGXCmDoxOMRiO#Wo7P4qRbVQ z*;QQ&6zUcQDij8qo?@T~po8Gbuns=@kf4_ydfYXp4Y2@$07Z)SQpj)$6h8I6{UevM zlC&r~SPp02eDBTQdv9jm??Rzw2GYMyjtT!b#xQ@uij{n3;l)iC!+gx}4DTv3qATkX z-C4Kj$$CU@)+_q5KCvm=B(ho7g&23yF9xy!z3eGAi@|JAFMEre7|MpkmTZd{&W3fG zuNV=J<=rkuY|Xaml%`_4*pclJk7tj&7&jv{@vLy-p_^eI!_P?BPN8$>q*bf`=ly(u zZ(erq2b~-|_Y3AB03X}n?5QJVgpQEWa!5wkkut(Z$cP-0(arnjne?&0Gn|oxB1p~U4N02k%{SiDyzjm<{~nBk6$N>v#7lX5 z2cXadKM(v~wCegLLvAJKZf!ATW~Z*zLNN`yO6FusX92Q`vh`GER=rkv)kZu7iH~im zTP_DLj!jQxmlNk=FJa_FBEn?0X-=7$4i?1g-GR zy*zF%?~u8;)@pZ|g@#2RT9L)#X4|~J6ESm-Vz{Y~Jep4~$VCDEP$e`kD3zEFk`N3+ zYyI(Jv49($E3M_Ejay;?bcw&UAQy^~#(~P1qGoxGwf5Hw_(iQ%5@e%0fj2<}*N)&s z2<`w0LY8)uQ}Cw+Ozv4;LVJ$IUe07zN}`atE!@p47vzj+s%qwra0@hAAWMsRp+>c) zO-dWGAPueG)moftM-m{GgP-&>$nG&;27AICdD)I4ZJX7iGKVUuFz;gz&uP{UT1213@OwBgT;pdTRCEE)A2DsnORCa-NvQ}-?ZF8Hl2lh^?+z91H6mF#28Ks?P_ijA(e#+5_ zS+(;m+WFS@Y?W)HTx#d8$_-O)SmB1NZC#(dsU)Y=?hCa0g4#As+olz6`pa;y5}mH3 zURT~&P*V%l)JUa24Zb6C27E{44ET=78Sou}GyiO6BAu`DJ0uBH-3(>w)x+UZ&=k@2 zzSsdX`*tqnBM*uG|D1|!8!#M&F5X>s*N$a0yM52sn!oKl9s;&@soV1M-d{M~jO|#Q z$SV!*3tW)xcyjjGcwd7w{i+OIHgLZ}n(Ykhq%}22L;KRxH;xU@Xg$@Wfm?2|sP+F& zSs%GbkBnAnCY}Yy?02p$xJQdZ zzV$+0%D{Wkzf>p+YjEMn*IgPJymz4Yc<~*`K4z9-93OOTxyr6ps2d5&HV4n(SppPY zU$GtQOYYye?{`DLu9vPDyolWeUh`sCS^!?yat@1++?spnyyhXLJLWq@zkIxGo-P(7 z880g{o3Z-icWAm;$}bkB87NqY3Fu71MZU)3^ z;{oQ-n>D^C`5n)0)1GJFuSAD!>i=xuWE#377cu)U2aQv+1|7>P`uEhclh{q|CH4oE zz7c~2xp9*Uo7dEs5$xbe3Oh%KN6@Ejo;2^8jtiIm)Yg2r1tN%PKS4L317z2SA7dC(hC?WH_Spv7dd>LCnc)Fig(QH`3& z0M-qe&3cm|REO0`4O?ucSb|qSg5FN^Eb_e81Un5u660ZmmrSk6h;V5hSR38$w4k*# zFljv!qBY+Vilwz>DJPcW8p)`UVHz3U_I;syu|F-`qzjwsLYXdGjR$9HFFVpNTe(dgLrmHThwZ2OWs*J=NR z+BZr20DS)%jxBkHCdVz#O8;5fKZUg(oKoK)?R(7vrq0pSG&c3Zm@Cd&JWb=H0Gz`W z8yKPkGYEuH)+kM2Q2mAq#m)*jn_EolE@Q>?4^Gi#B3CW8B&5OUSp&j(W*_`SZ62h}gZEeY6%mH@hHI3fXfHvw>E0}v?{LjV8( literal 0 HcmV?d00001 diff --git a/webinterface/minibase/project/forms.py b/webinterface/minibase/project/forms.py index e69de29b..ccc79d1d 100644 --- a/webinterface/minibase/project/forms.py +++ b/webinterface/minibase/project/forms.py @@ -0,0 +1,48 @@ +from flask_wtf import FlaskForm +from wtforms import SubmitField, SelectField, DateField, IntegerField, StringField +from wtforms.validators import DataRequired, Length, ValidationError +from flask_wtf.file import FileField, FileAllowed +import minibase.database.utils as dbUtils + + +class getCompanyNameForm(FlaskForm): # Defines the form class to be used for the user registretion + # Decalarion of the fields for the form and it's propereties + company = SelectField('Company Name', choices=dbUtils.getCompanyNames, validators=[DataRequired()]) + submit = SubmitField('Show Projects') + + +class getProjectNameForm(FlaskForm): # Defines the form class to be used for the user registretion + # Decalarion of the fields for the form and it's propereties + project = SelectField('Project Name', choices=dbUtils.getProjectOfSelectedCompany, validators=[DataRequired()]) + submit = SubmitField('Show Project details') + + +class projectRegisterForm(FlaskForm): + name = StringField('ProjectName', validators=[DataRequired(), Length(min=3, max=20)]) + description = StringField('ProjectName', validators=[DataRequired(), Length(min=3, max=300)]) + qtePrototype = IntegerField('Prototye Quantity', validators=[DataRequired()]) + datePrototye = DateField('Prototyping Date', validators=[DataRequired()]) + qteStart = IntegerField('Starting Quantity', validators=[DataRequired()]) + dateStart = DateField('Firts Starting Date', validators=[DataRequired()]) + qteStartProduction = IntegerField('Production Quantity', validators=[DataRequired()]) + dateProduction = DateField('Production Date', validators=[DataRequired()]) + company = SelectField('Company name', choices=dbUtils.getCompanyNames, validators=[DataRequired()]) + industry = SelectField('industry', choices=dbUtils.getIndustryNames, validators=[DataRequired()]) + picture = FileField('Update Profile Picture', validators=[FileAllowed(['jpg', 'png'])]) + submit = SubmitField('Register Project') + + +class projectUpdateForm(FlaskForm): + description = StringField('Description', validators=[DataRequired(), Length(min=3, max=300)]) + industry = SelectField('industry', validators=[DataRequired()]) + status = SelectField('Status', validators=[DataRequired()]) + responsible = SelectField('Repsonsible', validators=[DataRequired()]) + qtePrototype = IntegerField('Prototye Quantity', validators=[DataRequired()]) + datePrototype = DateField('Prototyping Date', validators=[DataRequired()]) + qteStart = IntegerField('Starting Quantity', validators=[DataRequired()]) + dateStart = DateField('Starting Date', validators=[DataRequired()]) + qteProduction = IntegerField('Production Quantity', validators=[DataRequired()]) + dateProduction = DateField('Production Date', validators=[DataRequired()]) + picture = FileField('Picture', validators=[FileAllowed(['jpg', 'png'])]) + submit = SubmitField('Update Project') + diff --git a/webinterface/minibase/project/routes.py b/webinterface/minibase/project/routes.py index 026bad8e..d71d4d08 100644 --- a/webinterface/minibase/project/routes.py +++ b/webinterface/minibase/project/routes.py @@ -1,37 +1,97 @@ -from flask import render_template, url_for, flash, redirect, request, Blueprint +from flask import render_template, url_for, flash, redirect, request, Blueprint, session from minibase import db from minibase.config import themeMinibase -from minibase.database.models import Company, Company_legal_entity, Company_relation,Company_status -from minibase.database.models import Industry, Note_status -from minibase.database.models import Person_role, Person_competence -from minibase.database.models import Project_status -from minibase.admin.forms import compLegalEntityForm, compRelationForm, industryRegisterForm,personRoleForm, personCompetenceForm, compStatusForm, noteStatusForm -from minibase.admin.forms import projectStatusForm +from minibase.project.forms import getProjectNameForm, getCompanyNameForm, projectUpdateForm +import minibase.database.utils as dbUtils +from minibase.database.models import Project, Company + # Declaring a blueprint project = Blueprint('project', __name__) -@admin.route("/register", methods=['GET', 'POST']) -def register(): - form = register() - legal_entities = Company_legal_entity.query.order_by(Company_legal_entity.name.asc()) +@project.route("/select_company", methods=['GET', 'POST']) +def select_company(): + form = getCompanyNameForm() if form.validate_on_submit(): - companyLegal = Company_legal_entity( - name=form.name.data, - description=form.description.data) - # Here we need to give the id of thr role as this is a foreign key - db.session.add(companyLegal) - db.session.commit() - - flash(f'{"Company Legal Entity registered!"}', 'success') - return render_template('admin/company_register_legal_entity.html', - title='Register Company Legal Entity', - legal_entities=legal_entities, - theme=themeMinibase, - form=form) + companyId = dbUtils.getCompanyId(form.company.data) + dbUtils.setSelectedCompany(companyId) + return redirect(url_for('project.select_project')) - return render_template('admin/company_register_legal_entity.html', - title='Register Company Legal Entity', - legal_entities=legal_entities, + return render_template('project/select_company.html', + title='Select Company Name', theme=themeMinibase, form=form) + + +@project.route("/select_project", methods=['GET', 'POST']) +def select_project(): + if dbUtils.getSelectedCompany(): # If a company is lesected + form = getProjectNameForm() + companyId = dbUtils.getSelectedCompany() + company_selected = dbUtils.getCompanyName(companyId) + if form.validate_on_submit(): + flash(f'{"Project Loaded"}', 'success') + projectId = dbUtils.getProjectId(companyId, form.project.data) + dbUtils.setSelectedProject(projectId) + return redirect(url_for('project.show_project')) + + return render_template('project/select_project.html', + title='Select Project Name for : ' + company_selected, + theme=themeMinibase, + form=form) + else: + return redirect(url_for('project.select_company')) + + + +@project.route("/show_project", methods=['GET', 'POST']) +def show_project(): + if dbUtils.getSelectedProject(): # If a project is lesected + form = projectUpdateForm() + projectId = dbUtils.getSelectedProject() + project = dbUtils.getProject(projectId) + image_file = url_for('static', filename='pics/' + project.image_file) + notes = dbUtils.getSelectedProjectNotes() + # To initiate choises as a list allow us to match it with the id's + form.responsible.choices = [(row.id, row.name +' '+row.last_name) for row in dbUtils.getEmployeesOfSelectedCompany()] + form.status.choices = [(row.id, row.name) for row in dbUtils.getProjectStatuses()] + form.industry.choices = [(row.id, row.name) for row in dbUtils.getIndustryNames()] + + if form.validate_on_submit(): + flash(f'{"Project Updated"}', 'success') + project.owner_id = int(form.responsible.data) + project.status_id = int(form.status.data) + project.description = form.description.data + project.qte_prototype = form.qtePrototype.data + project.qte_start = form.qteStart.data + project.qte_production = form.qteProduction.data + project.date_prototype = form.datePrototype.data + project.date_start = form.dateStart.data + project.date_production = form.dateProduction.data + db.session.add(project) + db.session.commit() + return redirect(url_for('project.show_project')) + elif request.method == 'GET': + form.responsible.data = str(project.owner_id) + form.status.data = str(project.status.id) + form.industry.data = str(project.industry_id) + form.description.data = project.description + form.qtePrototype.data = project.qte_prototype + form.qteStart.data = project.qte_start + form.qteProduction.data = project.qte_production + form.datePrototype.data = project.date_prototype + form.dateStart.data = project.date_start + form.dateProduction.data = project.date_production + + return render_template('project/show_project.html', + #title=project.belongs_to.name + ' : ' + project.name, + title="kerem", + companyName=project.belongs_to.name, + projectName=project.name, + projectId=project.id, + notes=notes, + image_file=image_file, + theme=themeMinibase, + form=form) + else: + return redirect(url_for('project.select_project')) diff --git a/webinterface/minibase/site.db b/webinterface/minibase/site.db index aaf4d73b31fc03fe701162760cd91d80c54826aa..bea23c6e8d1db8275dbdeb8fae002e3563f7f838 100644 GIT binary patch delta 261 zcmZY3A#MUu6oujY?wc|X+QJMB&_aP%45q07j{_tYfny((QDci5#Ue)GSwNHS0Mkv7 zknp3Mlg}J+a(3rf%1x!xJ1lItXB)C}D_qRMA8m1N8BRGD19} ff&?)d;IX{m6*aU(GV2xgXnk;9W)b%yZ~v+{A9Eel literal 290816 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 literal 0 HcmV?d00001 diff --git a/webinterface/minibase/templates/layout.html b/webinterface/minibase/templates/layout.html index 658b0204..f1197b18 100644 --- a/webinterface/minibase/templates/layout.html +++ b/webinterface/minibase/templates/layout.html @@ -1,5 +1,5 @@ - + @@ -69,8 +69,17 @@ Database - - +