added docs CUD
This commit is contained in:
47
caotek_mesavoirs/models/default.py
Normal file
47
caotek_mesavoirs/models/default.py
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
# -*- coding: utf8 -*-
|
||||||
|
from sqlalchemy import text
|
||||||
|
from sqlalchemy.ext.declarative import declarative_base
|
||||||
|
from sqlalchemy.orm import (
|
||||||
|
scoped_session,
|
||||||
|
sessionmaker,
|
||||||
|
)
|
||||||
|
|
||||||
|
from zope.sqlalchemy import ZopeTransactionExtension, mark_changed
|
||||||
|
|
||||||
|
from datetime import *
|
||||||
|
import transaction
|
||||||
|
|
||||||
|
def execute_query(request, query, params):
|
||||||
|
"""Execute query and mark session as changed"""
|
||||||
|
request.dbsession.execute(query, params)
|
||||||
|
mark_changed(request.dbsession)
|
||||||
|
transaction.commit()
|
||||||
|
|
||||||
|
def get_docs(request, doc_id):
|
||||||
|
"""Lire les doc"""
|
||||||
|
if doc_id == 0:
|
||||||
|
query = "SELECT * FROM docs ORDER BY theme, intitule;"
|
||||||
|
results = request.dbsession.execute(query).fetchall()
|
||||||
|
elif doc_id == -1:
|
||||||
|
query = "SELECT * FROM docs where theme <> 'INTERNE' ORDER BY theme, intitule;"
|
||||||
|
results = request.dbsession.execute(query).fetchall()
|
||||||
|
else:
|
||||||
|
query = "SELECT * FROM docs where doc_id = :doc_id;"
|
||||||
|
results = request.dbsession.execute(query, {'doc_id': doc_id}).first()
|
||||||
|
return results
|
||||||
|
|
||||||
|
def update_doc(request, doc_id, intitule, texte, theme):
|
||||||
|
"""créér ou modifier le doc"""
|
||||||
|
if doc_id == '0':
|
||||||
|
query = "INSERT INTO docs (intitule, texte, theme) VALUES(:intitule, :texte, :theme);"
|
||||||
|
execute_query(request, query, {'intitule': intitule, 'texte': texte, 'theme': theme})
|
||||||
|
else:
|
||||||
|
query = "update docs set intitule=:intitule, texte=:texte, theme=:theme where doc_id = :doc_id;"
|
||||||
|
execute_query(request, query, {'doc_id': doc_id, 'intitule': intitule, 'texte': texte, 'theme': theme})
|
||||||
|
|
||||||
|
def delete_doc(request, doc_id):
|
||||||
|
"""supprimer la doc"""
|
||||||
|
query = "delete from docs where doc_id = :doc_id;"
|
||||||
|
results = request.dbsession.execute(query, {'doc_id': doc_id})
|
||||||
|
|
||||||
|
|
||||||
@@ -13,11 +13,9 @@ from zope.sqlalchemy import (
|
|||||||
from datetime import *
|
from datetime import *
|
||||||
import transaction
|
import transaction
|
||||||
|
|
||||||
def execute_query(request, query, params):
|
from .default import (
|
||||||
"""Execute query and mark session as changed"""
|
execute_query,
|
||||||
request.dbsession.execute(query, params)
|
)
|
||||||
mark_changed(request.dbsession)
|
|
||||||
transaction.commit()
|
|
||||||
|
|
||||||
def get_member_by_mdp_oublie(request, lien):
|
def get_member_by_mdp_oublie(request, lien):
|
||||||
query = "SELECT * FROM members WHERE mdp_oublie=:lien;"
|
query = "SELECT * FROM members WHERE mdp_oublie=:lien;"
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
def includeme(config):
|
def includeme(config):
|
||||||
config.add_static_view('static', 'static', cache_max_age=3600)
|
config.add_static_view('static', 'static', cache_max_age=3600)
|
||||||
config.add_route('home', '/')
|
config.add_route('home', '/')
|
||||||
|
config.add_route('doc_edit', '/doc_edit/{doc_id}')
|
||||||
|
config.add_route('doc_list', '/doc_list')
|
||||||
|
config.add_route('doc_view', '/doc_view/{doc_id}')
|
||||||
# members
|
# members
|
||||||
config.add_route('changer_mdp', '/changer_mdp')
|
config.add_route('changer_mdp', '/changer_mdp')
|
||||||
config.add_route('envoyer_mdp', '/envoyer_mdp')
|
config.add_route('envoyer_mdp', '/envoyer_mdp')
|
||||||
|
|||||||
75
caotek_mesavoirs/templates/doc_edit.pt
Normal file
75
caotek_mesavoirs/templates/doc_edit.pt
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
<metal:block use-macro="main_template">
|
||||||
|
<div metal:fill-slot="content">
|
||||||
|
|
||||||
|
<div class="alert alert-danger" tal:condition="message" tal:content="message" />
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<form id="doc_edit-form" action="${url}" method="post" class="form-horizontal">
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-xs-2" for="intitule">Intitulé</label>
|
||||||
|
<div class="col-xs-8">
|
||||||
|
<input class="form-control" type="text" id="intitule" name="intitule" value="${intitule}"
|
||||||
|
placeholder="40 caractères maximum"
|
||||||
|
data-fv-notempty="true"
|
||||||
|
data-fv-notempty-message="L'intitule est obligatoire"
|
||||||
|
data-fv-stringlength="true"
|
||||||
|
data-fv-stringlength-max="40"
|
||||||
|
data-fv-stringlength-message="40 caractères maximum" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-xs-2" for="doc-text">Texte</label>
|
||||||
|
<div class="col-xs-8">
|
||||||
|
<textarea class="form-control" rows="15" cols="40" id="doc-text" name="texte"
|
||||||
|
data-fv-notempty="true"
|
||||||
|
data-fv-notempty-message="Le texte est obligatoire"
|
||||||
|
data-fv-stringlength="true"
|
||||||
|
data-fv-stringlength-max="30000"
|
||||||
|
data-fv-stringlength-message="30000 caractères maximum">${texte}
|
||||||
|
</textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-xs-2" for="theme">Thème</label>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<select class="form-control" id="theme" name="theme">
|
||||||
|
<div tal:repeat="item themes">
|
||||||
|
<option value="${item}" tal:attributes="selected theme==item and 'selected' or None">${item}</option>
|
||||||
|
</div>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-sm-offset-2 col-sm-8">
|
||||||
|
<button class="btn btn-primary" type="submit" name="form.submitted">
|
||||||
|
<span class="glyphicon glyphicon-ok"></span> Enregistrer</button>
|
||||||
|
<a href="${request.application_url}/doc_view/${doc_id}" class="btn btn-default" role="button">
|
||||||
|
<span class="glyphicon glyphicon-chevron-left"></span> Annuler</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group" tal:condition="doc_id<>'0'">
|
||||||
|
<div class="col-sm-offset-2 col-sm-8">
|
||||||
|
<button class="btn btn-warning" type="submit" name="form.deleted">
|
||||||
|
<span class="glyphicon glyphicon-remove"></span> Supprimer</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
</div> <!-- row -->
|
||||||
|
|
||||||
|
<script>
|
||||||
|
$(document).ready(function() {
|
||||||
|
$('#doc_edit-form').formValidation();
|
||||||
|
$('form input').on('keypress', function(e) {
|
||||||
|
return e.which !== 13;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</metal:block>
|
||||||
31
caotek_mesavoirs/templates/doc_list.pt
Normal file
31
caotek_mesavoirs/templates/doc_list.pt
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<metal:block use-macro="main_template">
|
||||||
|
<div metal:fill-slot="content">
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<p>
|
||||||
|
<a href="doc_edit/0" class="btn btn-success" role="button">
|
||||||
|
<span class="glyphicon glyphicon-plus"></span>
|
||||||
|
Créér une nouvelle doc</a>
|
||||||
|
</p>
|
||||||
|
<table class="table table-condensed table-striped table-bordered">
|
||||||
|
<tr>
|
||||||
|
<th>Intitule</th>
|
||||||
|
<th>Thème</th>
|
||||||
|
<th>Dernière mise à jour</th>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr tal:repeat="ligne docs">
|
||||||
|
<td><a href="doc_view/${ligne.doc_id}">${ligne.intitule}</a></td>
|
||||||
|
<td>${ligne.theme}</td>
|
||||||
|
<td><span tal:content="ligne.modif_le.strftime('%d/%m/%Y %H:%M')" /></td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</metal:block>
|
||||||
|
|
||||||
21
caotek_mesavoirs/templates/doc_view.pt
Normal file
21
caotek_mesavoirs/templates/doc_view.pt
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<metal:block use-macro="main_template">
|
||||||
|
<div metal:fill-slot="content">
|
||||||
|
|
||||||
|
<br />
|
||||||
|
<a href="${request.application_url}/doc_list" class="btn btn-default" role="button">
|
||||||
|
<span class="glyphicon glyphicon-chevron-left"></span> Fermer</a>
|
||||||
|
<a href="${request.application_url}/doc_edit/${doc_id}" class="btn btn-primary" role="button">
|
||||||
|
<span class="glyphicon glyphicon-pencil"></span> Modifier</a>
|
||||||
|
<br />
|
||||||
|
<hr>
|
||||||
|
<div tal:replace="structure texte">
|
||||||
|
Page text goes here.
|
||||||
|
</div>
|
||||||
|
<hr>
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</metal:block>
|
||||||
@@ -10,7 +10,6 @@
|
|||||||
|
|
||||||
<!-- Bootstrap core + Plug-ins CSS -->
|
<!-- Bootstrap core + Plug-ins CSS -->
|
||||||
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
|
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
|
||||||
<link href="//cdnjs.cloudflare.com/ajax/libs/fullcalendar/3.1.0/fullcalendar.min.css" rel="stylesheet">
|
|
||||||
<link href="//cdnjs.cloudflare.com/ajax/libs/bootstrap-datetimepicker/4.17.47/css/bootstrap-datetimepicker.min.css" rel="stylesheet">
|
<link href="//cdnjs.cloudflare.com/ajax/libs/bootstrap-datetimepicker/4.17.47/css/bootstrap-datetimepicker.min.css" rel="stylesheet">
|
||||||
<link href="${request.static_url('caotek_mesavoirs:static/dist/datatable/dataTables.bootstrap.css')}" rel="stylesheet" media="all">
|
<link href="${request.static_url('caotek_mesavoirs:static/dist/datatable/dataTables.bootstrap.css')}" rel="stylesheet" media="all">
|
||||||
<link href="${request.static_url('caotek_mesavoirs:static/dist/formvalidation/css/formValidation.min.css')}" rel="stylesheet">
|
<link href="${request.static_url('caotek_mesavoirs:static/dist/formvalidation/css/formValidation.min.css')}" rel="stylesheet">
|
||||||
@@ -21,11 +20,9 @@
|
|||||||
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script>
|
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script>
|
||||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
|
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
|
||||||
|
|
||||||
<!-- Bootstrap Fullcalendar plugin -->
|
<!-- Bootstrap moment plugin -->
|
||||||
<script src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.17.1/moment.min.js"></script>
|
<script src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.17.1/moment.min.js"></script>
|
||||||
<script src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.17.1/locale/fr.js"></script>
|
<script src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.17.1/locale/fr.js"></script>
|
||||||
<script src="//cdnjs.cloudflare.com/ajax/libs/fullcalendar/3.1.0/fullcalendar.min.js"></script>
|
|
||||||
<script src="//cdnjs.cloudflare.com/ajax/libs/fullcalendar/3.1.0/locale/fr.js"></script>
|
|
||||||
<!-- Bootstrap Datepicker plugin -->
|
<!-- Bootstrap Datepicker plugin -->
|
||||||
<script src="//cdnjs.cloudflare.com/ajax/libs/bootstrap-datetimepicker/4.17.47/js/bootstrap-datetimepicker.min.js"></script>
|
<script src="//cdnjs.cloudflare.com/ajax/libs/bootstrap-datetimepicker/4.17.47/js/bootstrap-datetimepicker.min.js"></script>
|
||||||
<!-- Datatable -->
|
<!-- Datatable -->
|
||||||
@@ -57,8 +54,9 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="collapse navbar-collapse" id="myNavbar" tal:condition="not layout.isAnonymous()">
|
<div class="collapse navbar-collapse" id="myNavbar" tal:condition="not layout.isAnonymous()">
|
||||||
<ul class="nav navbar-nav navbar-right">
|
<ul class="nav navbar-nav navbar-right">
|
||||||
<li><a href="${request.application_url}"><span class="glyphicon glyphicon-home"></span> ACTIFS</a></li>
|
<li><a href="${request.application_url}">ACTIFS</a></li>
|
||||||
<li><a href="${request.application_url}/allocation"><span class="glyphicon glyphicon-list-alt"></span> ALLOCATION</a></li>
|
<li><a href="${request.application_url}/allocation">ALLOCATION</a></li>
|
||||||
|
<li><a href="${request.application_url}/doc_list">DOCS</a></li>
|
||||||
${panel('dropdown_menu_panel')}
|
${panel('dropdown_menu_panel')}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<ul class="dropdown-menu">
|
<ul class="dropdown-menu">
|
||||||
<li class="dropdown-header">
|
<li class="dropdown-header">
|
||||||
${logged_in}<br />
|
${logged_in}<br />
|
||||||
Fonction: ${logged_in_fonction}
|
${logged_in_fonction}
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li class="divider"></li>
|
<li class="divider"></li>
|
||||||
|
|||||||
@@ -19,9 +19,12 @@ from pyramid_mailer import get_mailer
|
|||||||
from pyramid_mailer.message import Message, Attachment
|
from pyramid_mailer.message import Message, Attachment
|
||||||
from datetime import *
|
from datetime import *
|
||||||
import hashlib
|
import hashlib
|
||||||
|
from docutils.core import publish_parts
|
||||||
|
|
||||||
from sqlalchemy.exc import DBAPIError
|
from sqlalchemy.exc import DBAPIError
|
||||||
from ..security import groupfinder
|
from ..security import groupfinder
|
||||||
|
|
||||||
|
from ..models.default import *
|
||||||
from ..models.members import (
|
from ..models.members import (
|
||||||
get_member_by_email,
|
get_member_by_email,
|
||||||
)
|
)
|
||||||
@@ -64,6 +67,81 @@ def home(request):
|
|||||||
'page_title': u"%s %s" % (membre.prenom, membre.nom),
|
'page_title': u"%s %s" % (membre.prenom, membre.nom),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@view_config(route_name='doc_list', renderer='../templates/doc_list.pt', permission='view')
|
||||||
|
def doc_list(request):
|
||||||
|
|
||||||
|
# lire toutes les docs
|
||||||
|
docs = get_docs(request, 0)
|
||||||
|
|
||||||
|
return {
|
||||||
|
'page_title': u"Documents",
|
||||||
|
'docs': docs,
|
||||||
|
}
|
||||||
|
|
||||||
|
@view_config(route_name='doc_edit', renderer='../templates/doc_edit.pt', permission='view')
|
||||||
|
def doc_edit(request):
|
||||||
|
doc_id = request.matchdict['doc_id']
|
||||||
|
url = request.route_url('doc_edit',doc_id=doc_id)
|
||||||
|
|
||||||
|
message = u""
|
||||||
|
if doc_id == '0':
|
||||||
|
titre = "Nouvelle doc"
|
||||||
|
intitule = u""
|
||||||
|
texte = u""
|
||||||
|
theme = u""
|
||||||
|
else:
|
||||||
|
titre = "Modifier la doc : %s" % str(doc_id)
|
||||||
|
doc = get_docs(request, doc_id)
|
||||||
|
intitule = doc.intitule
|
||||||
|
texte = doc.texte
|
||||||
|
theme = doc.theme
|
||||||
|
|
||||||
|
if 'form.submitted' in request.params:
|
||||||
|
intitule = request.params["intitule"]
|
||||||
|
texte = request.params["texte"]
|
||||||
|
theme = request.params["theme"]
|
||||||
|
|
||||||
|
if len(intitule) > 0 and len(texte) > 0:
|
||||||
|
update_doc(request, doc_id, intitule, texte, theme)
|
||||||
|
return HTTPFound(location=request.route_url('doc_list')
|
||||||
|
else:
|
||||||
|
message = "Veuillez saisir un intitule et un texte."
|
||||||
|
|
||||||
|
if 'form.deleted' in request.params:
|
||||||
|
if doc_id <> '0':
|
||||||
|
delete_doc(request, doc_id)
|
||||||
|
request.session.flash(u"<%s> est supprimée avec succès." % intitule, 'success')
|
||||||
|
return HTTPFound(location=request.route_url('doc_list')
|
||||||
|
|
||||||
|
return {
|
||||||
|
'page_title': titre,
|
||||||
|
'url': url,
|
||||||
|
'message': message,
|
||||||
|
'doc_id': doc_id,
|
||||||
|
'intitule': intitule,
|
||||||
|
'texte': texte,
|
||||||
|
'theme': theme,
|
||||||
|
'themes': ["CONDUITE","EXAMEN","RESULTAT","INTERNE"],
|
||||||
|
}
|
||||||
|
|
||||||
|
@view_config(route_name='doc_view', renderer='../templates/doc_view.pt', permission='view')
|
||||||
|
def doc_view(request):
|
||||||
|
doc_id = request.matchdict['doc_id']
|
||||||
|
current_route_path = request.current_route_path()
|
||||||
|
|
||||||
|
doc = get_docs(request, doc_id)
|
||||||
|
intitule = doc.intitule
|
||||||
|
# insèrer le path de static/img
|
||||||
|
img_path = 'image:: %s/static/img/' % request.application_url
|
||||||
|
|
||||||
|
texte = doc.texte.replace('image:: static/img/', img_path)
|
||||||
|
# convertir reST en HTML
|
||||||
|
texte = publish_parts(texte, writer_name='html')['html_body']
|
||||||
|
return {
|
||||||
|
'page_title': intitule,
|
||||||
|
'texte': texte,
|
||||||
|
'doc_id': doc_id,
|
||||||
|
}
|
||||||
|
|
||||||
def envoyerMail(request, destinataire, objet, corps):
|
def envoyerMail(request, destinataire, objet, corps):
|
||||||
body = u"""
|
body = u"""
|
||||||
|
|||||||
Reference in New Issue
Block a user