From d8ca5c80a5f98cb62e65392c3026286e07576eb0 Mon Sep 17 00:00:00 2001 From: tr4ck3ur Date: Sat, 4 Apr 2015 04:42:51 +0200 Subject: [PATCH] Added Salle Physical Salle Management Added Role Form for entities --- jm2l/__init__.py | 16 ++- jm2l/forms.py | 41 +++++- jm2l/models.py | 1 + jm2l/templates/Salles/list.mako | 90 ++++++++++++++ jm2l/templates/Salles/salle.mako | 58 +++++++++ jm2l/templates/Salles/salle_phy.mako | 61 +++++++++ jm2l/templates/edit_event.mako | 36 +++++- jm2l/templates/edit_tiers.mako | 180 +++++++++++++++++++++------ jm2l/templates/layout.mako | 2 +- jm2l/templates/view_tiers.mako | 9 +- jm2l/upload.py | 8 +- jm2l/views.py | 153 +++++++++++++++++++++-- 12 files changed, 593 insertions(+), 62 deletions(-) create mode 100644 jm2l/templates/Salles/list.mako create mode 100644 jm2l/templates/Salles/salle.mako create mode 100644 jm2l/templates/Salles/salle_phy.mako diff --git a/jm2l/__init__.py b/jm2l/__init__.py index 0301231..fbe0db6 100644 --- a/jm2l/__init__.py +++ b/jm2l/__init__.py @@ -56,12 +56,17 @@ def main(global_config, **settings): config.add_route('vote_logo', '/vote_logo/{num:\d+}') # HTML Routes - Staff - config.add_route('list_task', '/Staff') - config.add_route('handle_pole', '/Staff/poles{sep:/*}{pole_id:(\d+)?}') - config.add_route('handle_task', '/Staff/tasks{sep:/*}{task_id:(\d+)?}') - config.add_route('action_task', '/Staff/{action:(\w+)}/{task_id:(\d+)}') + config.add_route('list_task', '/Staff') + config.add_route('handle_pole', '/Staff/poles{sep:/*}{pole_id:(\d+)?}') + config.add_route('handle_task', '/Staff/tasks{sep:/*}{task_id:(\d+)?}') + config.add_route('action_task', '/Staff/{action:(\w+)}/{task_id:(\d+)}') config.add_route('action_task_area', '/Staff/pole/{action:(\w+)}/{pole_id:(\d+)}') + config.add_route('list_salles', '/ListSalles') + config.add_route('handle_salle', '/Salles{sep:/*}{salle_id:(\d+)?}') + config.add_route('handle_salle_phy', '/PhySalles{sep:/*}{salle_id:(\d+)?}') + config.add_route('action_salle', '/Salles/{action:(\w+)}/{salle_id:(\d+)}') + # HTML Routes - Public config.add_route('home', '/') config.add_route('presse', '/{year:\d+}/dossier-de-presse') @@ -73,7 +78,8 @@ def main(global_config, **settings): ## Events config.add_route('event', '/event/{year:\d+}/{event_id:([\w-]+)?}') - config.add_route('link_event', '/MesJM2L/{year:\d+}/{intervention:\w+}/link') + config.add_route('link_event_user', '/MesJM2L/{year:\d+}/{intervention:\w+}/link_user') + config.add_route('link_event_tiers', '/MesJM2L/{year:\d+}/{intervention:\w+}/link_tiers') config.add_route('edit_event', '/MesJM2L/{year:\d+}/{intervention:\w+}{sep:/*}{event_id:([\w-]+)?}') ## Entities diff --git a/jm2l/forms.py b/jm2l/forms.py index 51a40a4..5c625fb 100644 --- a/jm2l/forms.py +++ b/jm2l/forms.py @@ -79,6 +79,13 @@ class TiersMember(MyBaseForm): year_uid = SelectField(u'Année', coerce=int, choices=zip(range(2006,2016),range(2006,2016))) user_uid = TextField(u'user') role = TextField(u'Role') + +class TiersRole(MyBaseForm): + class Meta: + csrf = False + + year_uid = SelectField(u'Année', coerce=int, choices=zip(range(2006,2016),range(2006,2016))) + tiers_role = SelectField(u'Role', choices=TIERS_ROLE) class TiersChoice(MyBaseForm): class Meta: @@ -96,6 +103,13 @@ class AddIntervenant(MyBaseForm): event_uid = HiddenField() intervenant = SelectField(u'Intervenant', coerce=int ) +class AddTiers(MyBaseForm): + class Meta: + csrf = False + + event_uid = HiddenField() + tiers = SelectField(u'Entité', coerce=int ) + class ConfCreateForm(MyBaseForm): event_type = HiddenField() @@ -133,6 +147,29 @@ class ConfCreateForm(MyBaseForm): class ConfUpdateForm(ConfCreateForm): uid = HiddenField() +class SalleForm(MyBaseForm): + year_uid = SelectField(u'Année', coerce=int) + phy_salle_id = SelectField('Salle Physique', coerce=int) + place_type = SelectField('Type', choices=[('Conference','Conference'), + ('Stand','Stand'), ('Ateliers','Ateliers'), ('Autres','Autres') ]) + name = TextField('Nom de la salle', [validators.Length(min=1, max=40)], + filters=[strip_filter]) + description = TextAreaField('Description', + filters=[strip_filter]) + +class EditSalleForm(SalleForm): + salle_id = HiddenField() + +class SallePhyForm(MyBaseForm): + name = TextField('Nom de la salle', [validators.Length(min=1, max=40)], + filters=[strip_filter]) + nb_places = TextField('Nombre de places', [validators.Length(max=4)]) + description = TextAreaField('Description', + filters=[strip_filter]) + +class EditSallePhyForm(SallePhyForm): + uid = HiddenField() + class PlaceCreateForm(MyBaseForm): place_type = SelectField('Type', choices=PLACE_TYPE) @@ -342,7 +379,9 @@ class TiersForm(MyBaseForm): description = u"Vous pouvez insérer les détails" ) - membership = FieldList(FormField(TiersMember)) + membership = FieldList(FormField(TiersMember)) + + roles = FieldList(FormField(TiersRole)) class UpdateTiersForm(TiersForm): uid = HiddenField() diff --git a/jm2l/models.py b/jm2l/models.py index c57783b..481658b 100644 --- a/jm2l/models.py +++ b/jm2l/models.py @@ -345,6 +345,7 @@ class Salles(Base): created = Column(DateTime, default=datetime.datetime.now) last_change = Column(DateTime, default=datetime.datetime.now) + phy = relationship(SallePhy) @classmethod def by_id(cls, uid): return DBSession.query(cls).filter(cls.salle_id == uid).first() diff --git a/jm2l/templates/Salles/list.mako b/jm2l/templates/Salles/list.mako new file mode 100644 index 0000000..1bfd62b --- /dev/null +++ b/jm2l/templates/Salles/list.mako @@ -0,0 +1,90 @@ +# -*- coding: utf-8 -*- +<%inherit file="jm2l:templates/layout.mako"/> +<% +from slugify import slugify +%> + + Ajouter une Salle + +

Gestion des salles JM2L

+ +
+
+ +
+ + +
+ +% for Num, Entity in enumerate(sorted(DicSalle.keys(), key=lambda x:x.year_uid)): +
+

${Entity.year_uid}

+ + + + + + + + % if len(DicSalle[Entity])==0: + + + + % endif + % for Salle in DicSalle[Entity]: + + + + % if Salle.description: + + + + % endif + % endfor + +
+ Liste des salles +
+ Il n'y a pas de salle définie pour l'année ${Entity.year_uid} +
+ ${Salle.place_type or ""} ${Salle.name or ""} + ${len(Salle.allevents)} : [ + % for e in Salle.allevents: + ${e.uid}, + % endfor + ] +
+ % if Salle.phy_salle_id: + [ ${Salle.phy.name} ${Salle.phy.nb_places} places ] + % else: + [ Créer ] + % endif +
+
${Salle.description | n}
+
+% endfor +
+
+ +
+
+<%def name="jsAddOn()"> + + diff --git a/jm2l/templates/Salles/salle.mako b/jm2l/templates/Salles/salle.mako new file mode 100644 index 0000000..d033aec --- /dev/null +++ b/jm2l/templates/Salles/salle.mako @@ -0,0 +1,58 @@ +# -*- coding: utf-8 -*- +<%inherit file="jm2l:templates/layout.mako"/> +<%namespace name="helpers" file="jm2l:templates/helpers.mako"/> +<%def name="jsAddOn()"> + + + + +<%def name="cssAddOn()"> + + + + +
+
+ + + Retour à la liste + +% if 'salle_id' in form._fields.keys(): + + Supprimer cette salle + +%endif +% if 'salle_id' in form._fields.keys(): +

Editer une Salle

+% else: +

Ajouter une Salle

+%endif +<% +DicForm = { + 'year_uid': {'PlaceHolder':u"Année", "FieldStyle":"width:7em;", "ContainerStyle":"float:left;" }, + 'phy_salle_id': {'PlaceHolder':u"Salle Physique", "FieldStyle":"width:20em;", "ContainerStyle":"float:left;" }, + 'place_type': {'PlaceHolder':u"Type d'évenement","FieldStyle":"width:15em;" }, + 'name': {'PlaceHolder':u"Nom de la salle", "FieldStyle":"width:90%;" }, + 'description': {'PlaceHolder':u"Description", "ContainerStyle":"width:95%;min-height:150px;padding-top: 12px;", "ckeditor":"1" }, + } +%> + +% if 'salle_id' in form._fields.keys(): +
+ ${form.salle_id()} +%else: + +%endif + ${helpers.DisplayForm(form, DicForm)} + +
+
+ +
+ +
+ +
+
diff --git a/jm2l/templates/Salles/salle_phy.mako b/jm2l/templates/Salles/salle_phy.mako new file mode 100644 index 0000000..a7c1f47 --- /dev/null +++ b/jm2l/templates/Salles/salle_phy.mako @@ -0,0 +1,61 @@ +# -*- coding: utf-8 -*- +<%inherit file="jm2l:templates/layout.mako"/> +<%namespace name="helpers" file="jm2l:templates/helpers.mako"/> +<%def name="jsAddOn()"> + + + + +<%def name="cssAddOn()"> + + + + + + + + + +
+
+ + + Retour à la liste + +% if 'uid' in form._fields.keys(): +

Editer une Salle Physique

+% else: +

Ajouter une Salle Physique

+%endif +<% +DicForm = { + 'name': {'PlaceHolder':u"Nom de la salle", "FieldStyle":"width:25em;", "ContainerStyle":"float:left;" }, + 'nb_places': {'PlaceHolder':u"Nombre de places", "FieldStyle":"width:10em;" }, + 'description': {'PlaceHolder':u"Description", "ContainerStyle":"width:95%;min-height:150px;padding-top: 12px;", "ckeditor":"1" }, + } +%> + +% if 'uid' in form._fields.keys(): +
+ ${form.uid()} +%else: + +%endif + ${helpers.DisplayForm(form, DicForm)} + +
+
+ +
+ +
+% if 'uid' in form._fields.keys(): +
+ ${helpers.uploader("salle", form.uid.data, u"Attachement" )} +
+%endif + +
+
diff --git a/jm2l/templates/edit_event.mako b/jm2l/templates/edit_event.mako index 6faa5d4..d1ace7f 100644 --- a/jm2l/templates/edit_event.mako +++ b/jm2l/templates/edit_event.mako @@ -99,12 +99,31 @@ DicForm = { % endif % if 'uid' in form._fields: + +
+ Indiquez l'entité dont vous faites la promotion : +

+

+ ${formAddT.event_uid} + + + +
+ NB : Notez que les entités séléctionnées apparaissent dans les exposants. +

+ +
+ +
Ajouter vos co-intervenants

Vous avez la possibilité d'être plusieurs pour un même évenement.
Chacun des intervenants doit être inscrit sur le site. -

+ ${formAdd.event_uid} @@ -134,6 +153,21 @@ DicForm = { \ No newline at end of file diff --git a/jm2l/templates/layout.mako b/jm2l/templates/layout.mako index b52168b..5d87bb3 100644 --- a/jm2l/templates/layout.mako +++ b/jm2l/templates/layout.mako @@ -233,7 +233,7 @@ HandleControls(); function handlevote() { currentIndex = $('div.active').index() + 1; $('.carousel-vote a').attr('href', "/vote_logo/" + currentIndex ) - if (currentIndex==${request.user.vote_logo}) { + if (currentIndex==${request.user.vote_logo or 0}) { $('.carousel-vote a').removeClass('btn-primary').addClass('btn-success') $('.carousel-vote a').html(" Mon préféré ! "); } else { diff --git a/jm2l/templates/view_tiers.mako b/jm2l/templates/view_tiers.mako index bb5636b..5b4811a 100644 --- a/jm2l/templates/view_tiers.mako +++ b/jm2l/templates/view_tiers.mako @@ -38,6 +38,13 @@ ${The_entity_type.entity_subtype}

Cette entité n'a pas de description.

% endif +
+ % if entity.website: +
+ ${entity.website} +
+ % endif +
% if 0: % for media in entity.PhotosLinks: @@ -87,7 +94,7 @@ ${The_entity_type.entity_subtype}

% endfor - +

Créé le ${entity.created.strftime('%d %b %Y').decode('utf-8')}



diff --git a/jm2l/upload.py b/jm2l/upload.py index 9cbfca5..b6f56b3 100644 --- a/jm2l/upload.py +++ b/jm2l/upload.py @@ -11,7 +11,7 @@ import magic import subprocess import cStringIO as StringIO # Database access imports -from .models import User, Place, Tiers, Event +from .models import User, Place, Tiers, Event, SallePhy MIN_FILE_SIZE = 1 # bytes MAX_FILE_SIZE = 500000000 # bytes @@ -84,11 +84,7 @@ class MediaPath(): if media_table=='place': slug = Place.by_id(linked_id).slug if media_table=='salle': - phyid = Salles.by_id(linked_id).phy_salle_id - if phyid: - slug = SallePhy.by_id(phyid) - else: - slug = linked_id + slug = SallePhy.by_id(linked_id).slug p = IMAGEPATH + [ media_table ] + [ slug ] elif media_table=='presse': # Use Year in linked_id diff --git a/jm2l/views.py b/jm2l/views.py index 8fee2a2..37b48b6 100644 --- a/jm2l/views.py +++ b/jm2l/views.py @@ -364,6 +364,74 @@ def action_task_area(request): DBSession.delete(Pole) return HTTPFound(location=request.route_url('list_task')) + +@view_config(route_name='list_salles', renderer='jm2l:templates/Salles/list.mako') +def list_salles(request): + DicSalle = {} + years = DBSession.query( JM2L_Year ).all() + for year in years: + salles = DBSession.query( Salles )\ + .filter( Salles.year_uid==year.year_uid )\ + .order_by(Salles.name).all() + DicSalle[year] = salles + return {'DicSalle': DicSalle } + +@view_config(route_name='handle_salle', renderer='jm2l:templates/Salles/salle.mako') +def handle_salle(request): + salle_id = request.matchdict.get('salle_id') + if salle_id: + Salle = Salles.by_id(int(salle_id)) + if not Salle: + raise HTTPNotFound() + form = EditSalleForm(request.POST, Salle, meta={'csrf_context': request.session}) + else: + Salle = Salles() + form = SalleForm(request.POST, Salle, meta={'csrf_context': request.session}) + form.year_uid.choices = map(tuple, DBSession.query(JM2L_Year.year_uid, JM2L_Year.year_uid).all()) + form.phy_salle_id.choices = map(tuple, DBSession.query(SallePhy.uid, SallePhy.name).all()) + if request.method == 'POST' and form.validate(): + form.populate_obj(Salle) + if 'uid' in form._fields.keys(): + DBSession.merge(Salle) + else: + DBSession.add(Salle) + return HTTPFound(location=request.route_url('list_salles')) + return {'form':form } + +@view_config(route_name='handle_salle_phy', renderer='jm2l:templates/Salles/salle_phy.mako') +def handle_salle_phy(request): + salle_id = request.matchdict.get('salle_id') + if salle_id: + Salle = SallePhy.by_id(int(salle_id)) + if not Salle: + raise HTTPNotFound() + form = EditSallePhyForm(request.POST, Salle, meta={'csrf_context': request.session}) + else: + Salle = SallePhy() + form = SallePhyForm(request.POST, Salle, meta={'csrf_context': request.session}) + + if request.method == 'POST' and form.validate(): + form.populate_obj(Salle) + Salle.slug = slugify(Salle.name) + if 'uid' in form._fields.keys(): + DBSession.merge(Salle) + else: + DBSession.add(Salle) + return HTTPFound(location=request.route_url('list_salles')) + return {'form':form } + +@view_config(route_name='action_salle') +def action_salle(request): + action = request.matchdict.get('action') + salle_id = request.matchdict.get('salle_id') + Salle = Salles.by_id(int(salle_id)) + if not Salle: + raise HTTPNotFound() + if action=='delete': + request.session.flash(('info', u'La Salle a été supprimée !')) + DBSession.delete(Salle) + return HTTPFound(location=request.route_url('list_salles')) + ## =-=- Here, We handle HTTP requests - User Logged Part -=-= @view_config(route_name='exchange', renderer="jm2l:templates/Logistique/Logistique.mako") def exchange(request): @@ -757,9 +825,9 @@ def show_event(request): 'event':TheEvent, 'logged_in':request.authenticated_userid } return MainTab -@view_config(route_name='link_event') -def link_event(request): - """ Create user if not exist, add it to current event """ +@view_config(route_name='link_event_user') +def link_event_user(request): + """ Get user and add it to current event """ year = int(request.matchdict.get('year', -1)) form = AddIntervenant(request.POST, meta={'csrf_context': request.session}) intervention = request.matchdict.get('intervention', None) @@ -778,6 +846,34 @@ def link_event(request): return HTTPFound(location=request.route_url('edit_event', sep='/', year=str(year), intervention=intervention, event_id=str(TargetEvent.uid))) + +@view_config(route_name='link_event_tiers') +def link_event_tiers(request): + """ Create user if not exist, add it to current event """ + year = int(request.matchdict.get('year', -1)) + form = AddTiers(request.POST, meta={'csrf_context': request.session}) + intervention = request.matchdict.get('intervention', None) + TargetEvent = Event.by_id(form.event_uid.data) + Exist = Tiers.by_id(form.tiers.data) + if not Exist: + request.session.flash(('error',u"Une erreur s'est produite lors de l'ajout de votre entitée !")) + return HTTPFound(location=request.route_url('edit_event', sep='/', + year=str(year), intervention=intervention, event_id=str(TargetEvent.uid))) + else: + TargetTiers = Exist + + if len(DBSession.query(Role_Tiers)\ + .filter(Role_Tiers.year_uid==year)\ + .filter(Role_Tiers.tiers_role=="Exposant")\ + .filter(Role_Tiers.tiers_uid==TargetTiers.uid)\ + .all())==0: + tev = Role_Tiers(year_uid=year, tiers_role="Exposant", tiers_uid=TargetTiers.uid) + DBSession.add(tev) + + return HTTPFound(location=request.route_url('edit_event', sep='/', + year=str(year), intervention=intervention, event_id=str(TargetEvent.uid))) + + @view_config(route_name='edit_event', renderer="jm2l:templates/edit_event.mako") def edit_event(request): year = int(request.matchdict.get('year', -1)) @@ -836,6 +932,16 @@ def edit_event(request): # Put some users on form formAdd.intervenant.choices = [(u.uid, "%s %s" % (u.nom, u.prenom)) for u in Users] + + # Each event can get severals entities + formAddT = AddTiers(event_uid=TheEvent.uid) + # Build list of entities + # Get entities from db + TmpTiers = DBSession.query(Tiers)\ + .order_by('name').limit(10) + # Put some entities on form + formAddT.tiers.choices = [(u.uid, "%s %s" % (u.nom, u.prenom)) + for u in Users] else: TheEvent = Event() # prepare the form for creation @@ -849,6 +955,11 @@ def edit_event(request): duration=60 # No intervenant formAdd = None + formAddT = None + + SalleDispo = DBSession.query(Salles)\ + .filter(Salles.year_uid==year)\ + .order_by('name') if intervention=="Conference": form.duration.choices =[ @@ -861,27 +972,27 @@ def edit_event(request): form.duration.choices.append( (duration,u'Conférence (%d min)' % duration) ) if not form._fields.has_key("uid"): form.duration.data=60 + SalleDispo = SalleDispo.filter(Salles.place_type=='Conference') elif intervention=="Stand": form.duration.choices =[ (8*60, u'Toute la journée'), (4*60, u'une demi-journée') ] + SalleDispo = SalleDispo.filter(Salles.place_type=='Stand') elif intervention=="Atelier": form.duration.choices = map( lambda d:(d, u'Atelier (%dh%.2d)' % (d/60, d%60) ), \ [60, 90, 120, 150, 180, 210, 240] ) if not duration in map(lambda (d,y): d, form.duration.choices): form.duration.choices.append( (duration,u'Atelier (%dh%.2d)' % (duration/60, duration%60) ) ) + SalleDispo = SalleDispo.filter(Salles.place_type=='Ateliers') elif intervention=="Table_Ronde": form.duration.choices = map( lambda d:(d, u'Table ronde (%dh%.2d)' % (d/60, d%60) ), \ [60, 90, 120, 150] ) if not duration in map(lambda (d,y): d, form.duration.choices): - form.duration.choices.append( (duration,u'Table ronde (%dh%.2d)' % (duration/60, duration%60) ) ) + form.duration.choices.append( (duration,u'Table ronde (%dh%.2d)' % (duration/60, duration%60) ) ) + SalleDispo = SalleDispo.filter(Salles.place_type=='Conference') else: return HTTPForbidden(u"Pas encore disponible.") - - SalleDispo = DBSession.query(Salles)\ - .filter(Salles.year_uid==year)\ - .order_by('name') form.salle_uid.choices = [(s.salle_id, s.name) for s in SalleDispo] form.start_sel.choices = TimeSlots @@ -900,14 +1011,14 @@ def edit_event(request): uev.user_uid = request.user.uid TheEvent.interventions.append( uev ) DBSession.flush() - request.session.flash(('sucess','Votre intervention a été créee !')) + request.session.flash(('sucess',u'Votre intervention a été créee !')) return HTTPFound(location=request.route_url('edit_event', sep='/', year=str(year), intervention=intervention, event_id=str(TheEvent.slug))) else: DBSession.merge(TheEvent) MainTab = {'programme':'','presse':'', 'plan':'', 'participer':'', - 'event':TheEvent, 'form':form, 'formAdd':formAdd, + 'event':TheEvent, 'form':form, 'formAdd':formAdd, 'formAddT':formAddT, 'logged_in':request.authenticated_userid } return MainTab @@ -979,18 +1090,30 @@ def edit_tiers(request): #test_form = TiersForm(request.POST, TheTiers, meta={'csrf_context': request.session}) if request.method == 'POST' and form.validate(): - print request.POST ToDelete = list() + ToDeleteR = list() # First, we remove entries no more present for obj in form.membership.object_data: MatchEntry = filter( lambda x: x.object_data and x.object_data._sa_instance_state == obj._sa_instance_state, form.membership.entries ) if not MatchEntry: ToDelete.append(obj) + # For roles too + for obj in form.roles.object_data: + MatchEntry = filter( lambda x: x.object_data and x.object_data._sa_instance_state == obj._sa_instance_state, + form.roles.entries ) + if not MatchEntry: + ToDeleteR.append(obj) + # We should remove it as it's not in original data for obj in ToDelete: TheTiers.membership.remove(obj) DBSession.delete(obj) + # For roles too + for obj in ToDeleteR: + TheTiers.roles.remove(obj) + DBSession.delete(obj) + # Then, it's time to consider new entries for entry in form.membership.entries: if entry.object_data is None: @@ -998,6 +1121,14 @@ def edit_tiers(request): entry.object_data = TmpUser TheTiers.membership.append(TmpUser) form.membership.object_data = TheTiers.membership + # For roles too + for entry in form.roles.entries: + if entry.object_data is None: + TmpRole = Role_Tiers() + entry.object_data = TmpRole + TheTiers.roles.append(TmpRole) + form.roles.object_data = TheTiers.roles + form.populate_obj(TheTiers) # Handle Remove of accents TheTiers.slug = slugify(form.name.data)