Browse Source

Migration to python 3

feature/python-3-migration
tr4ck3ur des JM2L 3 years ago
parent
commit
ad9883ae09
37 changed files with 1670 additions and 1547 deletions
  1. +2
    -2
      jm2l/__init__.py
  2. +1
    -1
      jm2l/auth.py
  3. +127
    -113
      jm2l/badge.py
  4. +4
    -1
      jm2l/captcha.py
  5. +1
    -1
      jm2l/const.py
  6. +42
    -39
      jm2l/helpers.py
  7. +390
    -363
      jm2l/models.py
  8. +12
    -13
      jm2l/scripts/initializedb.py
  9. +1
    -1
      jm2l/templates/Errors/403.mako
  10. +1
    -1
      jm2l/templates/Errors/404.mako
  11. +12
    -12
      jm2l/templates/Interventions/Interventions.mako
  12. +1
    -1
      jm2l/templates/Logistique/Dialog_Covoit.mako
  13. +1
    -1
      jm2l/templates/Logistique/Dialog_Heberg.mako
  14. +2
    -2
      jm2l/templates/Logistique/Dialog_Matos.mako
  15. +17
    -17
      jm2l/templates/Logistique/Logistique.mako
  16. +4
    -4
      jm2l/templates/Logistique/Tables.mako
  17. +4
    -4
      jm2l/templates/Profil/Profil.mako
  18. +13
    -13
      jm2l/templates/Profil/Sejour.mako
  19. +1
    -1
      jm2l/templates/Public/Programme.mako
  20. +2
    -2
      jm2l/templates/Salles/list_phy.mako
  21. +2
    -2
      jm2l/templates/Salles/salle.mako
  22. +1
    -1
      jm2l/templates/Staff/compta.mako
  23. +1
    -1
      jm2l/templates/Staff/list.mako
  24. +3
    -3
      jm2l/templates/edit_event.mako
  25. +14
    -14
      jm2l/templates/helpers.mako
  26. +7
    -7
      jm2l/templates/jm2l.mako
  27. +16
    -16
      jm2l/templates/layout.mako
  28. +3
    -3
      jm2l/templates/mail_html.mako
  29. +3
    -3
      jm2l/templates/mail_plain.mako
  30. +1
    -1
      jm2l/templates/show_user.mako
  31. +2
    -2
      jm2l/templates/view_event.mako
  32. +1
    -1
      jm2l/templates/view_tiers.mako
  33. +1
    -1
      jm2l/templates/view_user.mako
  34. +4
    -1
      jm2l/to_print.py
  35. +172
    -168
      jm2l/upload.py
  36. +798
    -729
      jm2l/views.py
  37. +3
    -2
      setup.py

+ 2
- 2
jm2l/__init__.py View File

@@ -19,7 +19,7 @@ from pyramid.request import Request
from mako.template import Template
from .models import User
from jm2l.const import CurrentYear
from models import JM2L_Year
from .models import JM2L_Year

import logging

@@ -80,7 +80,7 @@ def main(global_config, **settings):
authorization_policy=authorization_policy
)
config.add_subscriber(add_renderer_globals, BeforeRender)
config.registry['mailer'] = mailer_factory_from_settings(settings)
# config.registry['mailer'] = mailer_factory_from_settings(settings)
config.registry['event_date'] = JM2L_Year.get_latest_jm2l_startdate()
sched = BackgroundScheduler()
sched.add_job(mailer_tasks, 'cron', day_of_week='fri', hour=18, args=[ config ])


+ 1
- 1
jm2l/auth.py View File

@@ -8,7 +8,7 @@ from pyramid_mailer import get_mailer
from pyramid_mailer.message import Attachment, Message
from .forms import UserPasswordForm
from passlib.hash import argon2
from security import check_logged
from .security import check_logged
import datetime
import re



+ 127
- 113
jm2l/badge.py View File

@@ -1,7 +1,11 @@
# -*- coding: utf8 -*-
from pyramid.httpexceptions import HTTPNotFound, HTTPForbidden
from pyramid.response import Response
import cStringIO as StringIO

try:
from StringIO import StringIO
except ImportError:
from io import StringIO
from pyramid.view import view_config
from .models import DBSession, User
from reportlab.pdfgen import canvas
@@ -12,78 +16,86 @@ import qrcode
import subprocess
from .upload import MediaPath
from jm2l.const import CurrentYear

# Create PDF container
EXPIRATION_TIME = 300 # seconds
EXPIRATION_TIME = 300 # seconds
WIDTH = 85 * mm
HEIGHT = 60 * mm
ICONSIZE = 10 * mm

def JM2L_Logo(canvas, Offset=(0,0)):

def JM2L_Logo(canvas, Offset=(0, 0)):
OffX, OffY = Offset
logoobject = canvas.beginText()
logoobject.setFont('Logo', 32)
logoobject.setFillColorRGB(.83,0,.33)
logoobject.setTextOrigin(OffX+5, OffY+17)
logoobject.setFillColorRGB(.83, 0, .33)
logoobject.setTextOrigin(OffX + 5, OffY + 17)
logoobject.textLines("JM2L")
canvas.drawText(logoobject)
yearobject = canvas.beginText()
yearobject.setFont("Helvetica-Bold", 10)
yearobject.setFillColorRGB(1,1,1)
yearobject.setFillColorRGB(1, 1, 1)
yearobject.setTextRenderMode(0)
yearobject.setTextOrigin(OffX+12 , OffY+35)
yearobject.setTextOrigin(OffX + 12, OffY + 35)
yearobject.setWordSpace(13)
yearobject.textLines(" ".join(str(CurrentYear)))
canvas.drawText(yearobject)

def Tiers_Logo(canvas, DispUser, StartPos=None, Offset=(0,0)):

def Tiers_Logo(canvas, DispUser, StartPos=None, Offset=(0, 0)):
Border = 0
OffX, OffY = Offset
if StartPos is None:
StartPos = ( 30 * mm, 2 )
StartPos = (30 * mm, 2)
StartX, StartY = StartPos
MaxX, MaxY = 34*mm, 18*mm
MaxX, MaxY = 34 * mm, 18 * mm
num = 0
canvas.setStrokeColorRGB(0.5,0.5,0.5)
Logos = filter(lambda x:x.ThumbLinks, DispUser.tiers)[:3]
canvas.setStrokeColorRGB(0.5, 0.5, 0.5)
Logos = list()
for thumb in DispUser.tiers:
if thumb.ThumbLinks:
Logos.append(thumb.ThumbLinks[:3])
# Logos = list(filter(lambda x: x.ThumbLinks, DispUser.tiers)[:3])
# Should We compute a better positionning for logos ?
DicPos = {}
DicPos[1] = { 0:(1./2, 1./2) }
DicPos[2] = { 0:(1./3, 1./2), 1:(2./3, 1./2) }
DicPos[3] = { 0:(1./2, 1./4), 1:(1./3, 3./4), 2:(2./3, 3./4) }
DicPos[4] = { 0:(1./3, 1./4), 1:(2./3, 1./4), 2:(1./3, 3./4),
3:(2./3, 3./4) }
DicPos[5] = { 0:(1./3, 1./4), 1:(2./3, 1./4), 2:(1./6, 3./4),
3:(3./6, 3./4), 4:(5./6, 3./4) }
DicPos[6] = { 0:(1./6, 1./4), 1:(3./6, 1./4), 2:(5./6, 1./4),
3:(1./6, 3./4), 4:(3./6, 3./4), 5:(5./6, 3./4) }
DicPos[7] = { 0:(1./6, 1./4), 1:(3./6, 1./4), 2:(5./6, 1./4),
3:(1./8, 3./4), 4:(3./8, 3./4), 5:(5./8, 3./4),
6:(7./8, 3./4) }
DicPos[8] = { 0:(1./8, 1./4), 1:(3./8, 1./4), 2:(5./8, 1./4),
3:(7./8, 1./4), 4:(1./8, 3./4), 5:(3./8, 3./4),
6:(5./8, 3./4), 7:(7./8, 3./4) }
DicPos[1] = {0: (1. / 2, 1. / 2)}
DicPos[2] = {0: (1. / 3, 1. / 2), 1: (2. / 3, 1. / 2)}
DicPos[3] = {0: (1. / 2, 1. / 4), 1: (1. / 3, 3. / 4), 2: (2. / 3, 3. / 4)}
DicPos[4] = {0: (1. / 3, 1. / 4), 1: (2. / 3, 1. / 4), 2: (1. / 3, 3. / 4),
3: (2. / 3, 3. / 4)}
DicPos[5] = {0: (1. / 3, 1. / 4), 1: (2. / 3, 1. / 4), 2: (1. / 6, 3. / 4),
3: (3. / 6, 3. / 4), 4: (5. / 6, 3. / 4)}
DicPos[6] = {0: (1. / 6, 1. / 4), 1: (3. / 6, 1. / 4), 2: (5. / 6, 1. / 4),
3: (1. / 6, 3. / 4), 4: (3. / 6, 3. / 4), 5: (5. / 6, 3. / 4)}
DicPos[7] = {0: (1. / 6, 1. / 4), 1: (3. / 6, 1. / 4), 2: (5. / 6, 1. / 4),
3: (1. / 8, 3. / 4), 4: (3. / 8, 3. / 4), 5: (5. / 8, 3. / 4),
6: (7. / 8, 3. / 4)}
DicPos[8] = {0: (1. / 8, 1. / 4), 1: (3. / 8, 1. / 4), 2: (5. / 8, 1. / 4),
3: (7. / 8, 1. / 4), 4: (1. / 8, 3. / 4), 5: (3. / 8, 3. / 4),
6: (5. / 8, 3. / 4), 7: (7. / 8, 3. / 4)}
# draw overall border
# canvas.roundRect(StartX, StartY, MaxX, MaxY, radius=2, stroke=True)
for tiers in Logos:
FileName = tiers.ThumbLinks.pop().split("/")[-1]
ImagePath = "jm2l/upload/images/tiers/%s/%s" % (tiers.slug, FileName)
PosX = OffX+StartX + DicPos[len(Logos)][num][0] * MaxX - (ICONSIZE+Border)/2
PosY = OffY+StartY + DicPos[len(Logos)][num][1] * MaxY - (ICONSIZE+Border)/2
ImagePath = "jm2l/upload/images/tiers/%s/%s" % (tiers.slug, FileName)
PosX = OffX + StartX + DicPos[len(Logos)][num][0] * MaxX - (ICONSIZE + Border) / 2
PosY = OffY + StartY + DicPos[len(Logos)][num][1] * MaxY - (ICONSIZE + Border) / 2
canvas.setLineWidth(.1)
if len(Logos)>1:
if len(Logos) > 1:
size = ICONSIZE
else:
size = ICONSIZE*1.5
canvas.drawImage(ImagePath,
PosX, PosY, size, size,\
preserveAspectRatio=True,
anchor='c',
mask='auto'
)
size = ICONSIZE * 1.5
canvas.drawImage(ImagePath,
PosX, PosY, size, size,
preserveAspectRatio=True,
anchor='c',
mask='auto'
)
# draw icon border
# canvas.roundRect(PosX, PosY, ICONSIZE, ICONSIZE, radius=2, stroke=True)
num+=1
num += 1


def QRCode(DispUser):
qr = qrcode.QRCode(
@@ -98,78 +110,79 @@ def QRCode(DispUser):

return qr.make_image()

def one_badge(c, DispUser, Offset=(0,0)):

def one_badge(c, DispUser, Offset=(0, 0)):
# Logo on Top
JM2L_Logo(c, Offset)
OffX, OffY = Offset
c.rect(OffX-3, OffY-3, WIDTH+6, HEIGHT+6, fill=0, stroke=1)
c.rect(OffX - 3, OffY - 3, WIDTH + 6, HEIGHT + 6, fill=0, stroke=1)
if DispUser.Staff:
# Staff
c.setFillColorRGB(.83,0,.33)
c.rect(OffX-3, OffY+HEIGHT-30, WIDTH+6, 33, fill=1, stroke=0)
c.setFillColorRGB(1,1,1)
c.setFillColorRGB(.83, 0, .33)
c.rect(OffX - 3, OffY + HEIGHT - 30, WIDTH + 6, 33, fill=1, stroke=0)
c.setFillColorRGB(1, 1, 1)
c.setFont('Liberation', 30)
c.drawCentredString(OffX+WIDTH/2, OffY+HEIGHT-24, "STAFF")
c.drawCentredString(OffX + WIDTH / 2, OffY + HEIGHT - 24, "STAFF")
elif DispUser.is_Intervenant:
# Intervenant
c.setFillColorRGB(.21,.67,.78)
c.rect(OffX-3, OffY+HEIGHT-30, WIDTH+6, 33, fill=1, stroke=0)
c.setFillColorRGB(1,1,1)
c.setFillColorRGB(.21, .67, .78)
c.rect(OffX - 3, OffY + HEIGHT - 30, WIDTH + 6, 33, fill=1, stroke=0)
c.setFillColorRGB(1, 1, 1)
c.setFont('Liberation', 30)
c.drawCentredString(OffX+WIDTH/2, OffY+HEIGHT-24, "Intervenant")
c.drawCentredString(OffX + WIDTH / 2, OffY + HEIGHT - 24, "Intervenant")
elif DispUser.is_crew:
# Benevole
c.setFillColorRGB(.18,.76,.23)
c.rect(OffX-3, OffY+HEIGHT-30, WIDTH+6, 33, fill=1, stroke=0)
c.setFillColorRGB(1,1,1)
c.setFillColorRGB(.18, .76, .23)
c.rect(OffX - 3, OffY + HEIGHT - 30, WIDTH + 6, 33, fill=1, stroke=0)
c.setFillColorRGB(1, 1, 1)
c.setFont('Liberation', 30)
c.drawCentredString(OffX+WIDTH/2, OffY+HEIGHT-24, "Bénévole")
c.drawCentredString(OffX + WIDTH / 2, OffY + HEIGHT - 24, "Bénévole")
else:
# Visiteur
c.setFillColorRGB(.8,.8,.8)
c.rect(OffX-3, OffY+HEIGHT-30, WIDTH+6, 33, fill=1, stroke=0)
c.setFillColorRGB(1,1,1)
c.setFillColorRGB(.8, .8, .8)
c.rect(OffX - 3, OffY + HEIGHT - 30, WIDTH + 6, 33, fill=1, stroke=0)
c.setFillColorRGB(1, 1, 1)
c.setFont('Liberation', 30)
c.drawCentredString(OffX+WIDTH/2, OffY+HEIGHT-24, "Visiteur")
c.drawCentredString(OffX + WIDTH / 2, OffY + HEIGHT - 24, "Visiteur")

c.restoreState()
c.setFont('Liberation', 18)
c.setStrokeColorRGB(0,0,0)
c.setFillColorRGB(0,0,0)
c.setStrokeColorRGB(0, 0, 0)
c.setFillColorRGB(0, 0, 0)
# Feed Name and SurName
if DispUser.prenom and DispUser.nom and len(DispUser.prenom) + len(DispUser.nom)>18:
if DispUser.prenom and DispUser.nom and len(DispUser.prenom) + len(DispUser.nom) > 18:
if DispUser.pseudo:
c.drawCentredString(OffX+WIDTH/2, OffY+HEIGHT/2 + 0 * mm , "%s" % DispUser.prenom )
#c.setFont('Courier', 17)
c.drawCentredString(OffX+WIDTH/2, OffY+HEIGHT/2 - 8 * mm , "%s" % DispUser.nom )
c.drawCentredString(OffX + WIDTH / 2, OffY + HEIGHT / 2 + 0 * mm, "%s" % DispUser.prenom)
# c.setFont('Courier', 17)
c.drawCentredString(OffX + WIDTH / 2, OffY + HEIGHT / 2 - 8 * mm, "%s" % DispUser.nom)
else:
c.drawCentredString(OffX+WIDTH/2, OffY+HEIGHT/2 + 4 * mm , "%s" % DispUser.prenom )
#c.setFont('Courier', 17)
c.drawCentredString(OffX+WIDTH/2, OffY+HEIGHT/2 - 8 * mm , "%s" % DispUser.nom )
c.drawCentredString(OffX + WIDTH / 2, OffY + HEIGHT / 2 + 4 * mm, "%s" % DispUser.prenom)
# c.setFont('Courier', 17)
c.drawCentredString(OffX + WIDTH / 2, OffY + HEIGHT / 2 - 8 * mm, "%s" % DispUser.nom)
else:
c.drawCentredString(OffX+WIDTH/2, OffY+HEIGHT/2 + 0 * mm , "%s %s" % (DispUser.prenom, DispUser.nom) )
c.drawCentredString(OffX + WIDTH / 2, OffY + HEIGHT / 2 + 0 * mm, "%s %s" % (DispUser.prenom, DispUser.nom))

if DispUser.pseudo:
c.setFont("Helvetica-Oblique", 18)
c.drawCentredString(OffX+WIDTH/2, OffY+HEIGHT/2 + 10 * mm , "%s" % DispUser.pseudo )
# Put QR code to user profile
c.drawCentredString(OffX + WIDTH / 2, OffY + HEIGHT / 2 + 10 * mm, "%s" % DispUser.pseudo)
#  Put QR code to user profile
c.drawInlineImage(QRCode(DispUser), \
OffX+WIDTH - 20 * mm -5, OffY+5, \
20 * mm, 20 * mm, \
preserveAspectRatio=True, \
anchor='s')
Tiers_Logo(c, DispUser, None, Offset)
@view_config(route_name='badge_user', http_cache = (EXPIRATION_TIME, {'public':True}))
OffX + WIDTH - 20 * mm - 5, OffY + 5, \
20 * mm, 20 * mm, \
preserveAspectRatio=True, \
anchor='s')
Tiers_Logo(c, DispUser, None, Offset)
@view_config(route_name='badge_user') # , http_cache=(EXPIRATION_TIME, {'public': True}))
def badge_user(request):
isoutpng = request.params.get('png')
user_slug = request.matchdict.get('user_slug', None)
if user_slug is None or len(user_slug)==0:
if user_slug is None or len(user_slug) == 0:
raise HTTPNotFound(u"Cet utilisateur n'a pas été reconnu")
# Query database
DispUser = User.by_slug(user_slug)
@@ -177,48 +190,49 @@ def badge_user(request):
raise HTTPNotFound()

# Ok let's generate a PDF Badge
# Register LiberationMono font
ttfFile = "jm2l/static/fonts/LiberationMono-Regular.ttf"
pdfmetrics.registerFont(TTFont("Liberation", ttfFile))
# Import font
#  Import font
ttfFile_Logo = "jm2l/static/fonts/PWTinselLetters.ttf"
pdfmetrics.registerFont(TTFont("Logo", ttfFile_Logo))

pdf = StringIO.StringIO()
out_img = StringIO.StringIO()
c = canvas.Canvas( pdf, pagesize=(WIDTH, HEIGHT) )
pdf = StringIO()
out_img = StringIO()
c = canvas.Canvas(pdf, pagesize=(WIDTH, HEIGHT))
c.translate(mm, mm)
# Feed some metadata
c.setCreator("linux-azur.org")
c.setTitle("Badge")

c.saveState()
one_badge(c, DispUser)

one_badge(c, DispUser)
OutPDF = MediaPath().get_mediapath("badge", DispUser.uid, 'badge.pdf')
c.showPage()
c._filename = OutPDF
c.save()
pdf.seek(0)
if isoutpng:
OutPDF = MediaPath().get_mediapath("badge", DispUser.uid, 'badge.pdf')
OutPNG = MediaPath().get_mediapath("badge", DispUser.uid, 'badge.png')
# Let's generate a png file for website
with open( OutPDF ,'wb') as pdff:
pdff.write(pdf.read())
Command = ["convert","-density","150x150", OutPDF, OutPNG]
#  Let's generate a png file for website
with open("./%s" % OutPDF, 'wb') as pdff:
pdff.write(bytes(pdf.read(), 'utf8')) # .encode('utf8'))
Command = ["convert", "-density", "150x150", OutPDF, OutPNG]
subprocess.call(Command)
with open( OutPNG, 'rb') as pngfile:
out_img.write(pngfile.read())
with open("./%s" % OutPNG, 'r') as pngfile:
out_img.write(bytes(pngfile.read(), 'utf8')) # bytes(pngfile.read(), "utf8"))
out_img.seek(0)
return Response(app_iter=out_img, content_type = 'image/png' )
return Response(app_iter=out_img, content_type='image/png')
else:
return Response(app_iter=pdf, content_type = 'application/pdf' )
return Response(app_iter=pdf, content_type='application/pdf')


@view_config(route_name='all_badges')
@@ -234,32 +248,32 @@ def planche_badge(request):
# Register LiberationMono font
ttfFile = "jm2l/static/fonts/LiberationMono-Regular.ttf"
pdfmetrics.registerFont(TTFont("Liberation", ttfFile))
# Import font
#  Import font
ttfFile_Logo = "jm2l/static/fonts/PWTinselLetters.ttf"
pdfmetrics.registerFont(TTFont("Logo", ttfFile_Logo))
pdf = StringIO.StringIO()

FULLWIDTH = 210 * mm
FULLHEIGHT = 297 * mm

c = canvas.Canvas( pdf, pagesize=(FULLWIDTH, FULLHEIGHT) )
c = canvas.Canvas(pdf, pagesize=(FULLWIDTH, FULLHEIGHT))
c.translate(mm, mm)
# Feed some metadata
c.setCreator("linux-azur.org")
c.setTitle("Badge")
t=0
t = 0
ListUser = filter(lambda x: x.is_Intervenant or x.Staff or x.is_crew, Users)
for num, DispUser in enumerate(ListUser):
c.saveState()
Offsets = (((num-t)%2)*(WIDTH+40)+40, ((num-t)/2)*(HEIGHT+25)+40)
Offsets = (((num - t) % 2) * (WIDTH + 40) + 40, ((num - t) / 2) * (HEIGHT + 25) + 40)
one_badge(c, DispUser, Offsets)
if num%8==7:
t=num+1
if num % 8 == 7:
t = num + 1
c.showPage()

c.showPage()
c.save()
pdf.seek(0)
return Response(app_iter=pdf, content_type = 'application/pdf' )
return Response(app_iter=pdf, content_type='application/pdf')

+ 4
- 1
jm2l/captcha.py View File

@@ -3,7 +3,10 @@

import random
from PIL import Image, ImageDraw, ImageFont, ImageFilter
import cStringIO as StringIO
try:
from StringIO import StringIO
except ImportError:
from io import StringIO
import math
from pyramid.view import view_config
from .words import TabMots


+ 1
- 1
jm2l/const.py View File

@@ -1 +1 @@
CurrentYear = 2018
CurrentYear = 2020

+ 42
- 39
jm2l/helpers.py View File

@@ -4,61 +4,63 @@ from datetime import timedelta, datetime
import itertools
from jm2l.const import CurrentYear


class DummySejour(object):
def __init__(self, event):
self.Me = event['request'].user
self.CurrentEventYear = DBSession.query(JM2L_Year).filter(JM2L_Year.state=='Ongoing').first()
self.CurrentEventYear = DBSession.query(JM2L_Year).filter(JM2L_Year.state == 'Ongoing').first()
self.Sejour = None
if self.Me:
self.Sejour = DBSession.query(Sejour)\
.filter(Sejour.user_id==self.Me.uid)\
.filter(Sejour.for_year==self.CurrentEventYear.year_uid)\
self.Sejour = DBSession.query(Sejour) \
.filter(Sejour.user_id == self.Me.uid) \
.filter(Sejour.for_year == self.CurrentEventYear.year_uid) \
.first()


class Sejour_helpers(DummySejour):

def __init__(self, event):
super(Sejour_helpers, self).__init__(event)
if self.Sejour and self.Sejour.arrival_time is None:
self.Sejour = None
def StartEvent(self):
# This function return the start of the event
return self.CurrentYear
def PossibleDate(self, typedate="arrival"):
arrival, departure = False, False
TabResult = list()
if typedate == "arrival":
# Let's say people should arrive until 2 day before
arrival = True
myDayRange = xrange(2,-1,-1)
myDayRange = range(2, -1, -1)
elif typedate == "departure":
# Let's say people should go back home until 2 day after
departure = True
myDayRange = xrange(3)
departure = True
myDayRange = range(3)
else:
return TabResult
if self.Sejour:
ArrDate = datetime.strftime(self.Sejour.arrival_time,"%d %B %Y").decode('utf-8')
DepDate = datetime.strftime(self.Sejour.depart_time,"%d %B %Y").decode('utf-8')
ArrDate = datetime.strftime(self.Sejour.arrival_time, "%d %B %Y")
DepDate = datetime.strftime(self.Sejour.depart_time, "%d %B %Y")
else:
ArrDate = datetime.strftime( self.CurrentEventYear.start_time,"%d %B %Y" ).decode('utf-8')
DepDate = datetime.strftime( self.CurrentEventYear.end_time,"%d %B %Y" ).decode('utf-8')
ArrDate = datetime.strftime(self.CurrentEventYear.start_time, "%d %B %Y")
DepDate = datetime.strftime(self.CurrentEventYear.end_time, "%d %B %Y")
for oneday in myDayRange:
if arrival:
TmpDay = self.CurrentEventYear.end_time - timedelta(days=oneday)
elif departure:
TmpDay = self.CurrentEventYear.start_time + timedelta(days=oneday)
DayName = datetime.strftime(TmpDay,"%A")
DayNum = datetime.strftime(TmpDay,"%d/%m/%y")
DayString = datetime.strftime(TmpDay,"%d %B %Y").decode('utf-8')
if arrival and ArrDate==DayString:
DayName = datetime.strftime(TmpDay, "%A")
DayNum = datetime.strftime(TmpDay, "%d/%m/%y")
DayString = datetime.strftime(TmpDay, "%d %B %Y")
if arrival and ArrDate == DayString:
TabResult.append((DayNum, DayName, 'selected="selected"'))
elif departure and DepDate==DayString:
elif departure and DepDate == DayString:
TabResult.append((DayNum, DayName, 'selected="selected"'))
else:
TabResult.append((DayNum, DayName, ""))
@@ -67,21 +69,21 @@ class Sejour_helpers(DummySejour):
def PossibleTime(self, typedate="arrival"):
ArrTime, DepTime = "10:00", "19:00"
TabResult = list()
if self.Sejour:
ArrTime = datetime.strftime(self.Sejour.arrival_time,"%H:%M")
DepTime = datetime.strftime(self.Sejour.depart_time,"%H:%M")
ArrTime = datetime.strftime(self.Sejour.arrival_time, "%H:%M")
DepTime = datetime.strftime(self.Sejour.depart_time, "%H:%M")
for hour in range(24):
for minutes in range(0,60,10):
for minutes in range(0, 60, 10):
StrTime = "%.2d:%.2d" % (hour, minutes)
DispTime = "%dh%.2d" % (hour, minutes)
if typedate == "arrival" and StrTime==ArrTime:
TabResult.append( (StrTime, DispTime, 'selected="selected"') )
elif typedate == "departure" and StrTime==DepTime:
TabResult.append( (StrTime, DispTime, 'selected="selected"') )
if typedate == "arrival" and StrTime == ArrTime:
TabResult.append((StrTime, DispTime, 'selected="selected"'))
elif typedate == "departure" and StrTime == DepTime:
TabResult.append((StrTime, DispTime, 'selected="selected"'))
else:
TabResult.append( (StrTime, DispTime, "") )
TabResult.append((StrTime, DispTime, ""))
return TabResult

def IsCheck(self, InputControl):
@@ -91,13 +93,13 @@ class Sejour_helpers(DummySejour):
return ""
if self.Sejour:
if InputControl.startswith('Arrival'):
CtrlVal = 2**ListControlB.index(InputControl[8:])
CtrlVal = 2 ** ListControlB.index(InputControl[8:])
if self.Sejour.arrival_check & CtrlVal == CtrlVal:
return "checked=\"checked\""
else:
return ""
elif InputControl.startswith('Departure'):
CtrlVal = 2**ListControlB.index(InputControl[10:])
CtrlVal = 2 ** ListControlB.index(InputControl[10:])
if self.Sejour.depart_check & CtrlVal == CtrlVal:
return "checked=\"checked\""
else:
@@ -107,6 +109,7 @@ class Sejour_helpers(DummySejour):
else:
return ""


class Orga_helpers(DummySejour):

def __init__(self, event):
@@ -129,10 +132,10 @@ class Orga_helpers(DummySejour):
u"Faire du café et s'assurer de sa disponibilité.",
u"Participer à la publication / au montage des vidéos des conférenciers.",
u"Autres"
]
]

def IsChecked(self, nb):
nb = 2**nb
nb = 2 ** nb
if self.Sejour and self.Sejour.orga_part:
if self.Sejour.orga_part & nb == nb:
return "checked=\"checked\""
@@ -140,12 +143,12 @@ class Orga_helpers(DummySejour):
return ""
else:
return ""
def ChoosedList(self):
""" Return choice validated by user """
ListOrga = []
for num in range(0,len(self.Orga_tasks)):
curs = 2**num
for num in range(0, len(self.Orga_tasks)):
curs = 2 ** num
if self.Sejour.orga_part & curs == curs:
ListOrga.append(self.Orga_tasks[num])
return ListOrga
return ListOrga

+ 390
- 363
jm2l/models.py
File diff suppressed because it is too large
View File


+ 12
- 13
jm2l/scripts/initializedb.py View File

@@ -48,14 +48,14 @@ def pull_data(from_db, to_db, tables):
destination, dengine = make_session(to_db)

for table_name in tables:
print 'Processing', table_name
print 'Pulling schema from source server'
print('Processing', table_name)
print('Pulling schema from source server')
table = Table(table_name, smeta, autoload=True)
print 'Creating table on destination server'
print('Creating table on destination server')
table.metadata.create_all(dengine)
NewRecord = quick_mapper(table)
columns = table.columns.keys()
print 'Transferring records'
print('Transferring records')
for record in source.query(table).all():
data = dict(
[(str(column), getattr(record, column)) for column in columns]
@@ -69,20 +69,20 @@ def pull_data(from_db, to_db, tables):
try:
destination.merge(NewRecord(**data))
except:
print data
print(data)
pass
print 'Committing changes'
print('Committing changes')
destination.commit()


def main(argv=sys.argv):
connection_string = "sqlite:////home/tr4ck3ur/Dev/jm2l/JM2L.sqlite"
connection_string = "sqlite:////home/tr4ck3ur/git_repository/jm2l/JM2L.sqlite"
engine = create_engine(connection_string, echo=False, convert_unicode=True)
DBSession.configure(bind=engine)
Users = DBSession.query(User)
ListUser = filter(lambda x: x.is_Intervenant, Users)
for i in ListUser:
print i.mail
print(i.mail)

def main4(argv=sys.argv):
import csv
@@ -116,7 +116,7 @@ def main4(argv=sys.argv):
u.wifi_user = w_user
u.wifi_pass = w_pass
DBSession.merge(u)
print row, u
print(row, u)
finally:
f.close()
@@ -130,7 +130,7 @@ def main_3(argv=sys.argv):
connection_string = "sqlite:////home/tr4ck3ur/Dev/jm2l/JM2L.sqlite"
engine = create_engine(connection_string, echo=True, convert_unicode=True)
DBSession.configure(bind=engine)
p0, p1 = orm.aliased(User,name="p0"), orm.aliased(User ,name="p1")
p0, p1 = orm.aliased(User, name="p0"), orm.aliased(User , name="p1")
import pprint
## permtation
@@ -141,7 +141,7 @@ def main_3(argv=sys.argv):
.filter(p0.last_logged<p1.last_logged)\
.with_entities(p0.slug,p0.uid,p1.uid).all()
for slug, idsrc, iddst in Datas:
print slug
print(slug)
# Events
Events = DBSession.query(User_Event)\
.filter(User_Event.user_uid==idsrc)
@@ -238,5 +238,4 @@ def Initialize():
u.password = password
u.Staff = 0
DBSession.merge(u)
print u.nom, u.prenom, u.Staff
print(u.nom, u.prenom, u.Staff)

+ 1
- 1
jm2l/templates/Errors/403.mako View File

@@ -58,7 +58,7 @@
% if reason:
<p>${reason}</p>
% else:
<p>Vous n'êtes pas authentifi&eacute;, ou n'avez pas les authorisations n&eacute;cessaires.</p>
<p>Vous n'êtes pas authentifié, ou n'avez pas les authorisations nécessaires.</p>
% endif
</body>
</html>


+ 1
- 1
jm2l/templates/Errors/404.mako View File

@@ -54,7 +54,7 @@
</head>
<body>
<img src="/img/error404.png" width="200px" />
<h1>Page non trouv&eacute;e</h1>
<h1>Page non trouvée</h1>
% if reason:
<p>${reason}</p>
% else:


+ 12
- 12
jm2l/templates/Interventions/Interventions.mako View File

@@ -10,7 +10,7 @@
</thead>
<tbody>
<tr>
<td>Conf&eacute;rences</td> <td style="text-align:center">
<td>Conférences</td> <td style="text-align:center">
% if len( request.user.year_events('Conference') ):
% for evt in request.user.year_events('Conference'):
% endfor
@@ -106,11 +106,11 @@ elif Type=='T':
%>
% if Type!='O':
<fieldset>
<legend class="lowshadow">Vos ${CurTitles} programm&eacute;s pour ${CurrentYear}</legend>
<legend class="lowshadow">Vos ${CurTitles} programmés pour ${CurrentYear}</legend>
<%
Selection = filter(lambda x:(x.event_type==CurEventType and x.for_year==CurrentYear), uprofil.events)
Selection = list(filter(lambda x:(x.event_type==CurEventType and x.for_year==CurrentYear), uprofil.events))
HeadHistTitle = u"L'historique de vos %s ( %d ) " % ( CurTitles, len(Selection) )
NothingTitle = u"Vous n'avez pas sollicit&eacute; d'intervention %s." % CurEvent
NothingTitle = u"Vous n'avez pas sollicité d'intervention %s." % CurEvent
%>
${helpers.show_Interventions(Selection, "Sujet", NothingTitle )}
</fieldset>
@@ -118,21 +118,21 @@ NothingTitle = u"Vous n'avez pas sollicit&eacute; d'intervention %s." % CurEvent

% if Type=='C':
<p>
<strong>Proposer une conf&eacute;rence / un lighting talk</strong><br/>
<strong>Proposer une conférence / un lighting talk</strong><br/>
<ul>
<li>Si vous avez une exp&eacute;rience particulière avec les logiciels libres
<li>Si vous avez une expérience particulière avec les logiciels libres
que vous souhaitez partager.</li>
<li>Si vous êtes acteur d’un des sujets actuels qui menacent ou qui
promeuvent le logiciel libre.</li>
<li>Si vous voulez pr&eacute;senter un logiciel libre dont vous êtes l’auteur.</li>
<li>Si vous voulez présenter un logiciel libre dont vous êtes l’auteur.</li>
</ul>
Nous serons heureux de vous &eacute;couter.
Nous serons heureux de vous écouter.
<br>
Nous souhaitons proposer des conf&eacute;rences pour un public d&eacute;butant
Nous souhaitons proposer des conférences pour un public débutant
autant que pour des visiteurs avertis. Les sujets ne doivent pas
forc&eacute;ment être techniques, mais aussi d’ordre g&eacute;n&eacute;ral avec la seule
forcément être techniques, mais aussi d’ordre général avec la seule
contrainte de traiter de près ou de loin des logiciels libres, de la
communaut&eacute; ou de vos propres exp&eacute;riences d’utilisateur quotidien. <br>
communauté ou de vos propres exp&eacute;riences d’utilisateur quotidien. <br>
Le but de ces conf&eacute;rences est double :
<ul>
<li>donner confiance aux futurs utilisateurs de logiciels libres</li>
@@ -205,7 +205,7 @@ NothingTitle = u"Vous n'avez pas sollicit&eacute; d'intervention %s." % CurEvent
<fieldset>
<legend class="lowshadow">Historique</legend>
<%
Selection = filter(lambda x:(x.event_type==CurEventType and x.for_year!=CurrentYear), uprofil.events)
Selection = list(filter(lambda x:(x.event_type==CurEventType and x.for_year!=CurrentYear), uprofil.events))
HeadHistTitle = u"L'historique de vos %s ( %d ) " % ( CurTitles, len(Selection) )
NothingTitle = u"D&eacute;sol&eacute;, Il n'y a rien dans l'historique vous concernant."
%>


+ 1
- 1
jm2l/templates/Logistique/Dialog_Covoit.mako View File

@@ -30,7 +30,7 @@
</tbody>
</table>
<div class="center">
Pour un co-voiturage le <u>${Exch.start_time.strftime("%a %d %b").decode('utf-8')}</u>
Pour un co-voiturage le <u>${Exch.start_time.strftime("%a %d %b")}</u>
vers <strong>${Exch.start_time.strftime("%H:%M")}</strong>
</div>
Temps de voyage estimé à <span id="summary"></span>


+ 1
- 1
jm2l/templates/Logistique/Dialog_Heberg.mako View File

@@ -12,7 +12,7 @@
<dd>Un hébergement</dd>
% endif
<dt>Quand </dt>
<dd>La nuit du ${Exch.start_time.strftime('%A %d %b %Y').decode('utf-8')} jusqu'au lendemain</dd>
<dd>La nuit du ${Exch.start_time.strftime('%A %d %b %Y')} jusqu'au lendemain</dd>
% if Exch.description:
<dt>Détails </dt>
<dd>${Exch.description}</dd>


+ 2
- 2
jm2l/templates/Logistique/Dialog_Matos.mako View File

@@ -8,8 +8,8 @@
<dt>Catégorie</dt>
<dd>${Exch.Category.exch_subtype}</dd>
<dt>Quand </dt>
<dd>de ${Exch.start_time.strftime('%A %d %b %Y').decode('utf-8')} vers ${Exch.start_time.strftime('%Hh%M')}
à ${Exch.end_time.strftime('%A %d %b %Y').decode('utf-8')} vers ${Exch.end_time.strftime('%Hh%M')}
<dd>de ${Exch.start_time.strftime('%A %d %b %Y')} vers ${Exch.start_time.strftime('%Hh%M')}
à ${Exch.end_time.strftime('%A %d %b %Y')} vers ${Exch.end_time.strftime('%Hh%M')}
</dd>
<dt>Détails </dt>
<dd>${Exch.description}</dd>


+ 17
- 17
jm2l/templates/Logistique/Logistique.mako View File

@@ -8,11 +8,11 @@ DicExch = Exchanges.get_overview( request.user.uid )
<div class="tabbable tabs-left" id="Intendance_tab">
<ul class="nav nav-tabs navbar" style="margin-bottom:0;background-color: #f7f7f7;">
<li class="active"> <a href="#ResumeInt" data-toggle="tab">Resum&eacute;</a> </li>
<li class="active"> <a href="#ResumeInt" data-toggle="tab">Resumé</a> </li>
<li> <a href="#Miam" data-toggle="tab"><span style="font-size:1.8em;">&#127869;</span> Miam</a> </li>
<li> <a href="#Covoiturage" data-toggle="tab"><span style="font-size:1.8em;">&#128664;</span> Covoiturage</a> </li>
<li> <a href="#Hebergement" data-toggle="tab"><span style="font-size:1.8em;">&#127962;</span> H&eacute;bergement</a> </li>
<li> <a href="#Materiel" data-toggle="tab"><span style="font-size:1.8em;">&#128722;</span> Mat&eacute;riel</a> </li>
<li> <a href="#Hebergement" data-toggle="tab"><span style="font-size:1.8em;">&#127962;</span> Hébergement</a> </li>
<li> <a href="#Materiel" data-toggle="tab"><span style="font-size:1.8em;">&#128722;</span> Matériel</a> </li>
</ul>
<div class="tab-content">
@@ -30,7 +30,7 @@ DicExch = Exchanges.get_overview( request.user.uid )
${tables.DoTable(Type, 'Ask', DicExch)}
${tables.DoTable(Type, 'Proposal', DicExch)}
<fieldset>
<legend>Tous les &eacute;changes</legend>
<legend>Tous les échanges</legend>
${Missing(Type, DicExch['Missing'])}
</fieldset>
</%def>
@@ -59,23 +59,23 @@ DicForm = {
</td>
<td>
<p>
Compl&eacute;tez dès à pr&eacute;sent votre partie repas afin que l'on puisse faire les r&eacute;servations n&eacute;cessaires !
Complétez dès à présent votre partie repas afin que l'on puisse faire les réservations nécessaires !
</p>

<u>Vendredi soir :</u>
<p>
Certains conf&eacute;renciers viennent de très loin et seront pr&eacute;sent d&eacute;s le vendredi.<br />
Nous vous proposons de nous retrouver à proximit&eacute;, à la CASA.<br />
Certains conférenciers viennent de très loin et seront présent dés le vendredi.<br />
Nous vous proposons de nous retrouver à proximité, à la CASA.<br />
<a href="http://groupelacasa.com/la-carte-et-les-menus-1-2-75"> La carte CASA </a>
le vendredi soir autour d'un verre et d'un bon repas !
</p>
<u>Samedi Midi :</u>
<p>
&Agrave; la pause du midi, nous vous proposons un repas avec le food-truck 'les frères toqu&eacute;s' qui sera pr&eacute;sent sur le parking de PolyTech<br />
&Agrave; la pause du midi, nous vous proposons un repas avec le food-truck 'les frères toqués' qui sera présent sur le parking de PolyTech<br />
</p>
<u>Samedi Soir :</u>
<p>
Pour conclure la journ&eacute;e nous avons l'habitude de nous retrouver au repas de cloture.<br />
Pour conclure la journée nous avons l'habitude de nous retrouver au repas de cloture.<br />
Nous vous proposons de nous retrouver à Antibes au restaurant Les Tonnelles<br />
<a href="https://fr-fr.facebook.com/lestonnellesantibes/?_fb_noscript=1"> Les Tonnelles </a>
</p>
@@ -100,7 +100,7 @@ elif Type=='M':
<thead>
<tr>
<th colspan="5">
Les &eacute;changes ${CurTitle}
Les échanges ${CurTitle}
% if 0:
<span style="float:right;">
<a data-original-title="Afficher les demandes" data-toggle="tooltip" id="${Type}_Demande">
@@ -124,7 +124,7 @@ elif Type=='M':
<tr>
<th style="width:1em;"></th>
<th>D&eacute;tails</th>
<th>Détails</th>
<th style="width:1em;"></th>
<tr>
</thead>
@@ -132,7 +132,7 @@ elif Type=='M':
% if len(Selection)==0:
<tr>
<td colspan="5" style="text-align:center;">
<i>Il n'y a aucun &eacute;change ${CurTitle} propos&eacute; actuellement...</i>
<i>Il n'y a aucun échange ${CurTitle} proposé actuellement...</i>
</td>
</tr>
% else:
@@ -155,7 +155,7 @@ elif Type=='M':
<a href="/user/${item.provider.slug}"> ${item.provider.prenom} ${item.provider.nom} </a> offre
% endif
% if item.exch_type=="C":
un co-voiturage le ${item.start_time.strftime('%a %d %b vers %Hh%M').decode('utf-8')}
un co-voiturage le ${item.start_time.strftime('%a %d %b vers %Hh%M')}
de <a href="javascript:DoGetLieu('/${CurrentYear}/modal/Place/${item.Itin.start.place_id}')">${item.Itin.start.display_name}</a>
à <a href="javascript:DoGetLieu('/${CurrentYear}/modal/Place/${item.Itin.arrival.place_id}')">${item.Itin.arrival.display_name}</a>
% elif item.exch_type=="M":
@@ -165,8 +165,8 @@ elif Type=='M':
% if item.description:
${item.description[:30]}
% endif
de ${item.start_time.strftime('%a %d %b %Hh%M').decode('utf-8')}
à ${item.end_time.strftime('%a %d %b %Hh%M').decode('utf-8')}
de ${item.start_time.strftime('%a %d %b %Hh%M')}
à ${item.end_time.strftime('%a %d %b %Hh%M')}
% else:
% if item.Category:
<i>${item.Category.exch_subtype}</i>
@@ -174,7 +174,7 @@ elif Type=='M':
% if item.description:
${item.description[:30]}
% endif
${item.start_time.strftime('%a %d %b').decode('utf-8')} soir
${item.start_time.strftime('%a %d %b')} soir
% endif
</p>
</td>
@@ -284,7 +284,7 @@ ListWrap = ["Co-voiturage",u"Hébergement","Matos"]
</div>
<div class="accordion-group">
<div class="accordion-heading">
<a class="accordion-toggle" data-toggle="collapse" data-parent="#AccordionCounter" href="#collapseAll">Les compteurs de l´&eacute;v&eacute;nement</a>
<a class="accordion-toggle" data-toggle="collapse" data-parent="#AccordionCounter" href="#collapseAll">Les compteurs de l´év&eacute;nement</a>
</div>
<div id="collapseAll" class="accordion-body collapse">
<div class="accordion-inner">


+ 4
- 4
jm2l/templates/Logistique/Tables.mako View File

@@ -97,17 +97,17 @@ elif Type=='M':
</td>
<td>
%if Type=='C':
${item.start_time.strftime('%A %d %b %Y').decode('utf-8')} vers ${item.start_time.strftime('%Hh%M')}
${item.start_time.strftime('%A %d %b %Y')} vers ${item.start_time.strftime('%Hh%M')}
de <a href="javascript:DoGetLieu('/${CurrentYear}/modal/Place/${item.Itin.start.place_id}')">${item.Itin.start.display_name}</a>
à <a href="javascript:DoGetLieu('/${CurrentYear}/modal/Place/${item.Itin.arrival.place_id}')">${item.Itin.arrival.display_name}</a>
%elif Type=='H':
% if item.Category:
<i>${item.Category.exch_subtype}</i>,
% endif
La nuit du ${item.start_time.strftime('%A %d %b %Y').decode('utf-8')}<br>
La nuit du ${item.start_time.strftime('%A %d %b %Y')}<br>
%elif Type=='M':
de ${item.start_time.strftime('%A %d %b %Y').decode('utf-8')} vers ${item.start_time.strftime('%Hh%M')}
à ${item.end_time.strftime('%A %d %b %Y').decode('utf-8')} vers ${item.end_time.strftime('%Hh%M')}<br>
de ${item.start_time.strftime('%A %d %b %Y')} vers ${item.start_time.strftime('%Hh%M')}
à ${item.end_time.strftime('%A %d %b %Y')} vers ${item.end_time.strftime('%Hh%M')}<br>
${item.Category.exch_subtype}
%endif
%if item.description:


+ 4
- 4
jm2l/templates/Profil/Profil.mako View File

@@ -23,12 +23,12 @@
<%
DicFormA = {
'nom': {'PlaceHolder':u"Mon Nom", 'ContainerClass':"span6", 'next':False},
'prenom': {'PlaceHolder':u"Mon Pr&eacute;nom", 'ContainerClass':"span6", 'next':True},
'prenom': {'PlaceHolder':u"Mon Prénom", 'ContainerClass':"span6", 'next':True},
'pseudo': {'PlaceHolder':u"Mon Pseudo", 'ContainerClass':"span6", 'next':False},
'mail': {'PlaceHolder':u"mon.mail@fqdn.tld", 'ContainerClass':"span6", 'next':True},
'phone': {'PlaceHolder':u"0612345678", 'ContainerClass':"span6", 'next':False},
'website': {'PlaceHolder':u"http://ma-page-web.moi",'ContainerClass':"span6", 'next':True},
'gpg_key': {'PlaceHolder':u"Ma cl&eacute; gpg", 'ContainerClass':"span6", 'next':False},
'gpg_key': {'PlaceHolder':u"Ma clé gpg", 'ContainerClass':"span6", 'next':False},
'soc_link':{'PlaceHolder':u"#jm2l sur irc.freenode.org",'ContainerClass':"span6", 'next':True},
'bio': {'Ignore':True},
'tiersship': {'Ignore':True},
@@ -52,12 +52,12 @@ DicFormB = {

DicForm2 = {
'nom': {'PlaceHolder':u"Mon Nom", "FieldStyle":"width:16em;", 'ContainerStyle':"float:left;"},
'prenom': {'PlaceHolder':u"Mon Pr&eacute;nom", "FieldStyle":"width:16em;"},
'prenom': {'PlaceHolder':u"Mon Prénom", "FieldStyle":"width:16em;"},
'pseudo': {'PlaceHolder':u"Mon Pseudo", "FieldStyle":"width:16em;", 'ContainerStyle':"float:left;"},
'mail': {'PlaceHolder':u"mon.mail@fqdn.tld", "FieldStyle":"width:16em;"},
'phone': {'PlaceHolder':u"0612345678", "FieldStyle":"width:16em;", 'ContainerStyle':"float:left;"},
'website': {'PlaceHolder':u"http://ma-page-web.moi","FieldStyle":"width:16em;"},
'gpg_key': {'PlaceHolder':u"Ma cl&eacute; gpg", "FieldStyle":"width:90%;"},
'gpg_key': {'PlaceHolder':u"Ma clé gpg", "FieldStyle":"width:90%;"},
'soc_link':{'PlaceHolder':u"#jm2l sur irc.freenode.org","FieldStyle":"width:90%;"},
'bio': {'PlaceHolder':u"Ma Bilibiographie", "FieldStyle":"width:95%;min-height:150px;", "fieldset":True, "ckeditor":1 },
'tiersship': {'Ignore':True}


+ 13
- 13
jm2l/templates/Profil/Sejour.mako View File

@@ -14,14 +14,14 @@ fieldset:disabled {
% else:
<legend class="lowshadow">
<img style="max-height:50px;" src="/img/warn.png" alt="Attention !">
Vous n'avez pas confirm&eacute; votre venue aux JM2L ${CurrentYear}
Vous n'avez pas confirmé votre venue aux JM2L ${CurrentYear}
</legend>
<h4 class="lowshadow">Compl&eacute;tez et validez vite ce formulaire !</h4>
<h4 class="lowshadow">Complétez et validez vite ce formulaire !</h4>
% endif

<form id="ProfilForm" action="/MonSejour" method="POST">
<fieldset class="ComeToJM2L">
<legend>Arriv&eacute;e</legend>
<legend>Arrivée</legend>
<div class="form-inline">
J'arrive
<select style="width:12em;" id="Arrival:Place" name="Arrival:Place" title="Lieu">
@@ -63,16 +63,16 @@ fieldset:disabled {
<ul style="list-style-type: none;">
<li><label class="checkbox">
<input id="PMR" ${mytrip.IsCheck("Arrival:PMR")|n} name="Arrival:PMR" title="Assistance Personne à mobilit&eacute; r&eacute;duite (PMR)" type="checkbox">
d'assistance : Personne à mobilit&eacute; r&eacute;duite (PMR)</input></label>
<input id="PMR" ${mytrip.IsCheck("Arrival:PMR")|n} name="Arrival:PMR" title="Assistance Personne à mobilité réduite (PMR)" type="checkbox">
d'assistance : Personne à mobilité réduite (PMR)</input></label>
</li>
<li><label class="checkbox">
<input id="Cov" ${mytrip.IsCheck("Arrival:Cov")|n} name="Arrival:Cov" title="Covoiturage" type="checkbox">
d'un covoiturage, d'un h&eacute;bergement...<br>(j'ai rempli/je vais remplir la section Logistique).</input></label>
d'un covoiturage, d'un hébergement...<br>(j'ai rempli/je vais remplir la section Logistique).</input></label>
</li>
<li><label class="checkbox">
<input id="Bras" ${mytrip.IsCheck("Arrival:Bras")|n} name="Arrival:Bras" title="Bras" type="checkbox">
de bras, car je rapporte plein de mat&eacute;riel. <br>(Je transporte ma maison, mon garage ...)</input></label>
de bras, car je rapporte plein de matériel. <br>(Je transporte ma maison, mon garage ...)</input></label>
</li>
<li>
<div class="form-inline">
@@ -81,7 +81,7 @@ fieldset:disabled {
Autres
</input></label>
<input type="text" style="width:20em;" name="Arrival:Comment"
placeholder="Pr&eacute;cisions à propos de mon arriv&eacute;e…" />
placeholder="Précisions à propos de mon arrivée…" />
</div>
</li>
</ul>
@@ -90,7 +90,7 @@ fieldset:disabled {
</fieldset>
<fieldset class="ComeToJM2L">
<legend>D&eacute;part</legend>
<legend>Départ</legend>
<div class="form-inline">
Je repars
<select style="width:12em;" id="Departure:Place" class="formforform-field" name="Departure:Place" title="Alors, j'arrive">
@@ -130,8 +130,8 @@ fieldset:disabled {
Je vais avoir besoin: &nbsp;&nbsp;<small style="color: #aaa;">(Cochez les cases correspondantes)</small>
<ul style="list-style-type: none;">
<li><label class="checkbox">
<input id="PMR" ${mytrip.IsCheck("Departure:PMR")|n} name="Departure:PMR" title="d'Assistance : Personne à mobilit&eacute; r&eacute;duite (PMR)" type="checkbox">
d'assistance : Personne à mobilit&eacute; r&eacute;duite (PMR)</input>
<input id="PMR" ${mytrip.IsCheck("Departure:PMR")|n} name="Departure:PMR" title="d'Assistance : Personne à mobilité réduite (PMR)" type="checkbox">
d'assistance : Personne à mobilité réduite (PMR)</input>
</label>
</li>
<li><label class="checkbox">
@@ -141,7 +141,7 @@ fieldset:disabled {
</li>
<li><label class="checkbox">
<input id="Bras" ${mytrip.IsCheck("Departure:Bras")|n} name="Departure:Bras" title="de bras" type="checkbox">
de bras, car j'ai en stock plein de mat&eacute;riel (Ma maison).</input>
de bras, car j'ai en stock plein de matériel (Ma maison).</input>
</label>
</li>
<li>
@@ -151,7 +151,7 @@ fieldset:disabled {
Autres
</input></label>
<input type="text" style="width:20em;" name="Departure:Comment"
placeholder="Pr&eacute;cisions à propos de mon d&eacute;part…" />
placeholder="Précisions à propos de mon départ…" />
</div>
</li>
</ul>


+ 1
- 1
jm2l/templates/Public/Programme.mako View File

@@ -111,7 +111,7 @@ if Counter==0:
vid = event.video.first()
pres = event.presentation.first()
%>
${event.start_time.strftime("%a %d %b").decode('utf-8')}<br>
${event.start_time.strftime("%a %d %b")}<br>
${event.start_time.strftime("%H:%M")} - ${event.end_time.strftime("%H:%M")}
</td>
<td style="position: relative;">


+ 2
- 2
jm2l/templates/Salles/list_phy.mako View File

@@ -24,7 +24,7 @@ from slugify import slugify
% if len(DicSallePhy)==0:
<tr>
<td style="text-align:center;">
<i>Il n'y a pas de salle d&eacute;finie pour le moment.</i>
<i>Il n'y a pas de salle définie pour le moment.</i>
</td>
</tr>
% endif
@@ -43,7 +43,7 @@ from slugify import slugify
% if SallePhy.uid:
[ ${SallePhy.nb_places} places ]
% else:
[ <a href="/PhySalles">Cr&eacute;er</a> ]
[ <a href="/PhySalles">Créer</a> ]
% endif
</div>



+ 2
- 2
jm2l/templates/Salles/salle.mako View File

@@ -29,9 +29,9 @@
%endif
<%
DicForm = {
'year_uid': {'PlaceHolder':u"Ann&eacute;e", "FieldStyle":"width:7em;", "ContainerStyle":"float:left;" },
'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'&eacute;vènement","FieldStyle":"width:15em;" },
'place_type': {'PlaceHolder':u"Type d'évènement","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" },
}


+ 1
- 1
jm2l/templates/Staff/compta.mako View File

@@ -46,7 +46,7 @@
</td>
</tr>
% endif
% for item, one_dic in found.iteritems():
% for item, one_dic in found.items():
<tr>
<td>
<a href="/user/${item}">


+ 1
- 1
jm2l/templates/Staff/list.mako View File

@@ -63,7 +63,7 @@ from slugify import slugify
</a>
<span style="float:right;">
- <a href="/user/${task.assignee.slug}">${task.assignee.pseudo or ' '.join([task.assignee.prenom, task.assignee.nom]) }</a>
- ${task.due_date.strftime("%d %b").decode("utf-8")}
- ${task.due_date.strftime("%d %b")}
</span>
% endif
</td>


+ 3
- 3
jm2l/templates/edit_event.mako View File

@@ -30,7 +30,7 @@
%endif
% if 'uid' in form._fields:
<div class="borderboxtime">
${event.start_time.strftime('%d %b %Y').decode('utf-8')} -
${event.start_time.strftime('%d %b %Y')} -
${event.start_time.strftime('%H:%M')} à ${event.end_time.strftime('%H:%M')}
%if event.Salle:
- <strong>Salle</strong>: ${event.Salle.name}
@@ -184,10 +184,10 @@ DicForm = {

</fieldset>
<div class="clearfix">&nbsp;</div>
<p style="float:right;">Créé le ${event.created.strftime('%d %b %Y').decode('utf-8')}</p>
<p style="float:right;">Créé le ${event.created.strftime('%d %b %Y')}</p>
%else:
<p style="float:right;">Créé le
${datetime.now().strftime('%d %b %Y').decode('utf-8')}
${datetime.now().strftime('%d %b %Y')}
</p>
% endif
<br/>


+ 14
- 14
jm2l/templates/helpers.mako View File

@@ -7,7 +7,7 @@ TabJs = {'select':[], 'desc':[]}
%>
<div class="row-fluid">
% for FieldName, Field in form._fields.items():
% if DicFormat.has_key(Field.name) and DicFormat[Field.name].get("Ignore"):
% if Field.name in DicFormat and DicFormat[Field.name].get("Ignore"):
<% continue %>
% endif
% if Field.type in ['HiddenField', 'CSRFTokenField']:
@@ -27,7 +27,7 @@ TabJs = {'select':[], 'desc':[]}
</a>
% endif
</label>
% if DicFormat.has_key(Field.name):
% if Field.name in DicFormat:
<%
PlaceHolder = DicFormat[Field.name].get("PlaceHolder")
Class = [False,"ckeditor"][ "ckeditor" in DicFormat[Field.name] ]
@@ -49,7 +49,7 @@ TabJs = {'select':[], 'desc':[]}
% endfor
</div>

% if DicFormat.has_key(Field.name) and DicFormat[Field.name].get("next")==True:
% if Field.name in DicFormat and DicFormat[Field.name].get("next")==True:
</div>
<div class="row-fluid">
% endif
@@ -72,7 +72,7 @@ TabJs = {'select':[], 'desc':[]}
TabJs = {'select':[], 'desc':[]}
%>
% for FieldName, Field in form._fields.items():
% if DicFormat.has_key(Field.name) and DicFormat[Field.name].get("Ignore"):
% if Field.name in DicFormat and DicFormat[Field.name].get("Ignore"):
<% continue %>
% endif
% if Field.type in ['HiddenField', 'CSRFTokenField']:
@@ -81,11 +81,11 @@ TabJs = {'select':[], 'desc':[]}
% elif Field.type=="SelectField":
<% TabJs['select'].append(Field.label.field_id) %>
% endif
% if DicFormat.has_key(Field.name) and DicFormat[Field.name].get("fieldset"):
% if Field.name in DicFormat and DicFormat[Field.name].get("fieldset"):
<fieldset>
<legend>${Field.label.text}</legend>
% else:
% if DicFormat.has_key(Field.name) and DicFormat[Field.name].get("ContainerStyle"):
% if Field.name in DicFormat and DicFormat[Field.name].get("ContainerStyle"):
<div style="padding-right:5px;${DicFormat[Field.name].get("ContainerStyle")}">
% else:
<div style="padding-right:5px;">
@@ -101,7 +101,7 @@ TabJs = {'select':[], 'desc':[]}
% endif
</label>
% endif
% if DicFormat.has_key(Field.name):
% if Field.name in DicFormat:
<%
PlaceHolder = DicFormat[Field.name].get("PlaceHolder")
FieldStyle = DicFormat[Field.name].get("FieldStyle")
@@ -122,7 +122,7 @@ TabJs = {'select':[], 'desc':[]}
${ error }
</div>
% endfor
% if DicFormat.has_key(Field.name) and DicFormat[Field.name].get("fieldset"):
% if Field.name in DicFormat and DicFormat[Field.name].get("fieldset"):
</fieldset>
% else:
</div>
@@ -142,7 +142,7 @@ TabJs = {'select':[], 'desc':[]}
<%def name="sejour_wrapper(Places)">

<div class="form-inline">
D&eacute;part :
Départ :
<select style="width:12em;" id="Arrival:Place" name="Arrival:Place" title="Lieu">
% for place in Places:
<option value="${place.place_id}">${place.display_name}</option>
@@ -151,7 +151,7 @@ TabJs = {'select':[], 'desc':[]}
</div>
<br />
<div class="form-inline">
Arriv&eacute;e :
Arrivée :
<select style="width:12em;" id="Arrival:Place" name="Arrival:Place" title="Lieu">
% for place in Places:
<option value="${place.place_id}">${place.display_name}</option>
@@ -184,7 +184,7 @@ TabJs = {'select':[], 'desc':[]}
${itin_form.arrival_place(style='width:17em;')}
</div>
<div style="padding:5px;">
<small style="color:#999">Si je n´ai pas trouv&eacute; le lieu dont j´ai besoin dans ces listes...</small>
<small style="color:#999">Si je n´ai pas trouvé le lieu dont j´ai besoin dans ces listes...</small>
<br />
<small style="color:#999">Je peux </small>
<a class="btn btn-mini btn-info" role="button" href="javascript:DoGetLieu('/${CurrentYear}/modal/Place/0');">
@@ -350,9 +350,9 @@ TabJs = {'select':[], 'desc':[]}
<tr>
<td style="text-align:center;" colspan="2">
% if NotFoundTitle:
<i>${NotFoundTitle}</i>
<i>${NotFoundTitle | h}</i>
% else:
<i>D&eacute;sol&eacute;, Il n'y a rien dans l'historique.</i>
<i>Désolé;, Il n'y a rien dans l'historique.</i>
% endif
</td>
</tr>
@@ -366,7 +366,7 @@ TabJs = {'select':[], 'desc':[]}
vid = event.video.first()
pres = event.presentation.first()
%>
${event.start_time.strftime('%d %b %Y').decode('utf-8')}
${event.start_time.strftime('%d %b %Y')}
${start.hour}:${"%.2d" % start.minute}-${end.hour}:${"%.2d" % end.minute}
</td>
<td style="position: relative;">${event.event_type}:


+ 7
- 7
jm2l/templates/jm2l.mako View File

@@ -61,7 +61,7 @@
<div class="tabbable" id="main_tab">
<ul class="nav nav-tabs nav-pills" style="margin-bottom: 5px;">
<li class="active"><a href="#Profil" id="Map_Profil" data-toggle="tab">Mon Profil</a></li>
<li><a href="#Sejour" id="Map_Sejour" data-toggle="tab">Mon S&eacute;jour</a></li>
<li><a href="#Sejour" id="Map_Sejour" data-toggle="tab">Mon Séjour</a></li>
<li><a href="#Logistique" id="Map_Logistique" data-toggle="tab">Logistique</a></li>
<li><a href="#Interventions" id="Map_Interventions" data-toggle="tab">Mes Interventions</a></li>
<li><a href="#Frais" id="Map_Frais" data-toggle="tab">Mes Frais</a></li>
@@ -79,8 +79,8 @@
<div class="tabbable tabs-left" id="Interventions_tab">
<ul class="nav nav-tabs navbar" style="margin-bottom:0;">
<li class="active"> <a href="#ResumePart" data-toggle="tab">Resum&eacute;</a> </li>
<li> <a href="#Conference" data-toggle="tab">Conf&eacute;rence</a> </li>
<li class="active"> <a href="#ResumePart" data-toggle="tab">Resumé</a> </li>
<li> <a href="#Conference" data-toggle="tab">Conférence</a> </li>
<li> <a href="#Stand" data-toggle="tab">Stand</a> </li>
<li> <a href="#Atelier" data-toggle="tab">Atelier</a> </li>
<li> <a href="#TableRonde" data-toggle="tab">Table Ronde</a> </li>
@@ -118,12 +118,12 @@
<div class="tab-pane fade" id="Frais">
<fieldset>
<legend class="lowshadow">Une participation à mes frais ?</legend>
L'&eacute;quipe des JM2L participe aux <u>frais de transport</u> des intervenants !<br /><br />
L'équipe des JM2L participe aux <u>frais de transport</u> des intervenants !<br /><br />
Et bien oui, mais cette participation ne sera effective que si vous remplissez <u>toutes les conditions</u> suivantes:
<ul style="list-style:circle;">
<li>Vous animez <strong>un atelier, une conf&eacute;rence ou une table ronde</strong> aux JM2L ${CurrentYear}.</li>
<li>Votre fiche est renseign&eacute;e avec <strong>votre RIB</strong>.</li>
<li>Votre fiche est renseign&eacute;e avec <strong>les preuves</strong> de vos achats.</li>
<li>Vous animez <strong>un atelier, une conférence ou une table ronde</strong> aux JM2L ${CurrentYear}.</li>
<li>Votre fiche est renseignée avec <strong>votre RIB</strong>.</li>
<li>Votre fiche est renseignée avec <strong>les preuves</strong> de vos achats.</li>
<li>Vous <strong>présentez l'original de vos tickets</strong> à l'accueil pendant l'évènement.</li>
<li>Tous vos documents sont conformes.</li>
</ul>


+ 16
- 16
jm2l/templates/layout.mako View File

@@ -3,7 +3,7 @@
<%namespace name="helpers" file="jm2l:templates/helpers.mako"/>
<%
context._kwargs['postpone_js']=[]
DisplayYear = request.session.get('year', 2018)
DisplayYear = request.session.get('year', 2020)
%>
<head>
<title>JM2L ${DisplayYear}</title>
@@ -68,12 +68,12 @@ ${helpers.uploader_js()}
% if request.user and request.user.vote_logo not in [1,2,3]:
<div class="item active">
<div class="align-center">
<H1>JM2L 2017</H1>
<h3>Choisissez ici votre logo pr&eacute;f&eacute;r&eacute; !</h3>
<H1>JM2L 2020</H1>
<h3>Choisissez ici votre logo préféré !</h3>
<p>Utilisez les flèches pour choisir et voter !<br>
Vous pouvez changer à tout moment, mais vous n'aurez droit qu'a un seul choix, le vôtre ;)</p>
<p>Vous souhaitez proposer le vôtre ? <br>
N'h&eacute;sitez pas à envoyer vos propositions par mail à l'&eacute;quipe !</p>
N'hésitez pas à envoyer vos propositions par mail à l'équipe !</p>
</div>
</div>
% endif
@@ -105,10 +105,10 @@ ${helpers.uploader_js()}
<a class="btn dropdown-toggle" data-toggle="dropdown" href="#">
Édition&nbsp;<span class="caret"></span></a>
<ul class="dropdown-menu pull-right" style="min-width:0">
% for tmpyear in range(2018, 2005, -1):
% for tmpyear in range(2020, 2005, -1):
% if tmpyear==DisplayYear:
<li><a style="font-weight: bold;" href="/year/${tmpyear}">${tmpyear}</a></li>
% elif tmpyear!=2014 and tmpyear!=2016:
% elif tmpyear not in [2014, 2016, 2018, 2019]:
<li><a href="/year/${tmpyear}">${tmpyear}</a></li>
% endif
% endfor
@@ -128,17 +128,17 @@ ${helpers.uploader_js()}
% if request.user:
% if request.user.Staff:
<li><a href="/${DisplayYear}/Staff">Partie Staff</a></li>
<li><a href="/${DisplayYear}/ListParticipant">G&eacute;rer les intervenants</a></li>
<li><a href="/ListSalles">G&eacute;rer les salles</a></li>
<li><a href="/entities">G&eacute;rer les entit&eacute;s</a></li>
<li><a href="/${DisplayYear}/ListParticipant">Gérer les intervenants</a></li>
<li><a href="/ListSalles">Gérer les salles</a></li>
<li><a href="/entities">Gérer les entités</a></li>
<li><a href="/${DisplayYear}/ListOrga">Participations &agrave; l'orga</a></li>
<li><a href="/${DisplayYear}/Staff/compta">Comptabilit&eacute;</a></li>
<li><a href="/${DisplayYear}/Staff/compta">Comptabilité</a></li>
<li><a href="/ListSallesPhy">Les salles &agrave; Poly'tech</a></li>
<li role="separator" class="divider"></li>
% endif
<li><a href="/MesJM2L">Mon profil</a></li>
<li><a href="/user/${request.user.slug}">Mon profil public</a></li>
<li><a href="/sign/out">Me d&eacute;connecter</a></li>
<li><a href="/sign/out">Me déconnecter</a></li>
% else:
<li><a href="/participer-l-evenement#inscription">Je m'inscris</a></li>
<li><a href="/sign/login">Je m'identifie</a></li>
@@ -186,9 +186,9 @@ ${helpers.uploader_js()}

<footer class="footer">
<div class="container">
<h4>JM2L 2005-2018</h4>
<h4>JM2L 2005-2020</h4>
<p>
Concoct&eacute; par <a href="http://www.linux-azur.org/">Linux Azur</a> ~
Concocté par <a href="http://www.linux-azur.org/">Linux Azur</a> ~
<a href="http://creativecommons.org/licenses/by-sa/4.0/">CopyFriendly</a>
</p>
<p>
@@ -196,10 +196,10 @@ ${helpers.uploader_js()}
</p>
<p>
Conception et construction en <a href="http://git.linux-azur.org/JM2L/jm2l/src/master">DIY</a> ~
H&eacute;berg&eacute; par <a href="http://www.heberg-24.com/"> Heberg24 </a>
Hébergé par <a href="http://www.heberg-24.com/"> Heberg24 </a>
</p>
<p>
Vous avez trouv&eacute; un bug ? <a href="http://git.linux-azur.org/JM2L/jm2l/issues">Reportez-le ici</a>
Vous avez trouvé un bug ? <a href="http://git.linux-azur.org/JM2L/jm2l/issues">Reportez-le ici</a>
</p>
</div>
</footer>
@@ -245,7 +245,7 @@ function handlevote() {
$('.carousel-vote a').attr('href', "/vote_logo/" + currentIndex )
if (currentIndex==${request.user.vote_logo or 0}) {
$('.carousel-vote a').removeClass('btn-primary').addClass('btn-success')
$('.carousel-vote a').html("<i class='icon-ok icon-white'></i> Mon pr&eacute;f&eacute;r&eacute; ! ");
$('.carousel-vote a').html("<i class='icon-ok icon-white'></i> Mon préféré ! ");
} else {
$('.carousel-vote a').removeClass('btn-success').addClass('btn-primary');
$('.carousel-vote a').html("<i class='icon-star icon-white'></i> Je vote pour ce logo ! ");


+ 3
- 3
jm2l/templates/mail_html.mako View File

@@ -96,7 +96,7 @@ Voici ce qu'il y'a dans la liste des tâches qui te sont assignées:
% for t in sorted(User.task_assoc, key=lambda k:k.due_date):
% if not t.closed:
<tr>
<td>${t.due_date.strftime('%d %B %Y').decode('utf-8', 'xmlcharrefreplace')}</td><td>${t.area.name}</td>
<td>${t.due_date.strftime('%d %B %Y')}</td><td>${t.area.name}</td>
<td><a href="http://jm2l.linux-azur.org/2017/Staff/tasks/${t.uid}">${t.name}</a>
% endif
% endfor
@@ -107,7 +107,7 @@ Voici ce qu'il y'a dans la liste des tâches qui te sont assignées:
% for t in sorted(Contact.task_assoc, key=lambda k:k.due_date):
% if not t.closed:
<tr>
<td>${t.due_date.strftime('%d %B %Y').decode('utf-8', 'xmlcharrefreplace')}</td><td>${t.area.name}</td>
<td>${t.due_date.strftime('%d %B %Y')}</td><td>${t.area.name}</td>
<td><a href="http://jm2l.linux-azur.org/2017/Staff/tasks/${t.uid}">${t.name}</a>
% endif
% endfor
@@ -116,7 +116,7 @@ Voici ce qu'il y'a dans la liste des tâches qui te sont assignées:
Pour accéder à ton espace sur le site, il te suffit de cliquer sur le <a href="${request.route_url('bymail', hash=User.my_hash)}">lien suivant.</a>
<br/><br/>
% for t in filter(lambda k:k.uid==51, Contact.task_assoc):
Nous avons fixé la prochaine réunion JM2L au ${t.due_date.strftime('%d %B').decode('utf-8', 'xmlcharrefreplace')} à 19h30.
Nous avons fixé la prochaine réunion JM2L au ${t.due_date.strftime('%d %B')} à 19h30.
% endfor
<p>
Bon courage !


+ 3
- 3
jm2l/templates/mail_plain.mako View File

@@ -65,7 +65,7 @@ Voici ce qu'il y'a dans la liste des tâches qui te sont assignées:

% for t in sorted(User.task_assoc, key=lambda k:k.due_date):
% if not t.closed:
- Pour le ${t.due_date.strftime('%d %B %Y').decode('utf-8', 'xmlcharrefreplace')} - ${t.area.name} tâche ${t.uid}
- Pour le ${t.due_date.strftime('%d %B %Y')} - ${t.area.name} tâche ${t.uid}
=> ${t.name}
% endif
@@ -75,7 +75,7 @@ Et il y'a aussi des tâches communes !

% for t in sorted(Contact.task_assoc, key=lambda k:k.due_date):
% if not t.closed and t.uid!=51:
- Pour le ${t.due_date.strftime('%d %B %Y').decode('utf-8', 'xmlcharrefreplace')} - ${t.area.name} tâche ${t.uid}
- Pour le ${t.due_date.strftime('%d %B %Y')} - ${t.area.name} tâche ${t.uid}
=> ${t.name}
% endif
@@ -85,7 +85,7 @@ Pour accéder à ton espace il te suffit de cliquer sur le lien suivant :
${request.route_url('bymail', hash=User.my_hash)}.

% for t in filter(lambda k:k.uid==51, Contact.task_assoc):
Nous avons fixé la prochaine réunion JM2L au ${t.due_date.strftime('%d %B').decode('utf-8', 'xmlcharrefreplace')} à 19h30.
Nous avons fixé la prochaine réunion JM2L au ${t.due_date.strftime('%d %B')} à 19h30.
% endfor



+ 1
- 1
jm2l/templates/show_user.mako View File

@@ -52,7 +52,7 @@
</div>
<br/>
<hr/>
<p style="float:right;">Créé le ${DispUser.created.strftime('%d %b %Y').decode('utf-8')}</p>
<p style="float:right;">Créé le ${DispUser.created.strftime('%d %b %Y')}</p>

</div>
</div>

+ 2
- 2
jm2l/templates/view_event.mako View File

@@ -13,7 +13,7 @@
</div>
<strong>${event.event_type}</strong>:
<div class="borderboxtime">
${event.start_time.strftime('%d %b %Y').decode('utf-8')} -
${event.start_time.strftime('%d %b %Y')} -
${event.start_time.strftime('%H:%M')} à ${event.end_time.strftime('%H:%M')}
</div>
% if event.for_year==CurrentYear and request.user and (request.user.Staff or request.user in event.intervenants):
@@ -116,7 +116,7 @@
</p>
% endfor
<div class="clearfix">&nbsp;</div>
<p style="float:right;">Créé le ${event.created.strftime('%d %b %Y').decode('utf-8')}</p>
<p style="float:right;">Créé le ${event.created.strftime('%d %b %Y')}</p>
<br/>
<hr/>
</div>


+ 1
- 1
jm2l/templates/view_tiers.mako View File

@@ -103,7 +103,7 @@ ${The_entity_type.entity_subtype}
</p>
% endfor
<br/><br/>
<p style="float:right;">Créé le ${entity.created.strftime('%d %b %Y').decode('utf-8')}</p>
<p style="float:right;">Créé le ${entity.created.strftime('%d %b %Y')}</p>
<br/>
<hr/>



+ 1
- 1
jm2l/templates/view_user.mako View File

@@ -47,7 +47,7 @@
<h4>Ses interventions :</h4>
${helpers.show_Interventions(DispUser.events)}
% endif
<p style="float:right;">Créé le ${DispUser.created.strftime('%d %b %Y').decode('utf-8')}</p>
<p style="float:right;">Créé le ${DispUser.created.strftime('%d %b %Y')}</p>

</div>
</div>

+ 4
- 1
jm2l/to_print.py View File

@@ -1,6 +1,9 @@
# -*- coding: utf8 -*-
from pyramid.response import Response
import cStringIO as StringIO
try:
from StringIO import StringIO
except ImportError:
from io import StringIO
from pyramid.view import view_config
from .models import DBSession, Event, Salles
from reportlab.pdfgen import canvas


+ 172
- 168
jm2l/upload.py View File

@@ -9,113 +9,114 @@ from os import path
import mimetypes
import magic
import subprocess
import cStringIO as StringIO
try:
from StringIO import StringIO
except ImportError:
from io import StringIO
# Database access imports
from .models import User, Place, Tiers, Event, SallePhy
from .blenderthumbnailer import blend_extract_thumb, write_png
from jm2l.const import CurrentYear
from slugify import slugify

MIN_FILE_SIZE = 1 # bytes
MAX_FILE_SIZE = 500000000 # bytes
MIN_FILE_SIZE = 1 # bytes
MAX_FILE_SIZE = 500000000 # bytes
IMAGE_TYPES = re.compile('image/(gif|p?jpeg|(x-)?png)')
ACCEPTED_MIMES = ['application/pdf',
'application/vnd.oasis.opendocument.text',
'application/vnd.oasis.opendocument.text-template',
'application/vnd.oasis.opendocument.graphics',
'application/vnd.oasis.opendocument.graphics-template',
'application/vnd.oasis.opendocument.presentation',
'application/vnd.oasis.opendocument.presentation-template',
'application/vnd.oasis.opendocument.spreadsheet',
'application/vnd.oasis.opendocument.spreadsheet-template',
'image/svg+xml',
'application/x-blender'
]

'application/vnd.oasis.opendocument.text',
'application/vnd.oasis.opendocument.text-template',
'application/vnd.oasis.opendocument.graphics',
'application/vnd.oasis.opendocument.graphics-template',
'application/vnd.oasis.opendocument.presentation',
'application/vnd.oasis.opendocument.presentation-template',
'application/vnd.oasis.opendocument.spreadsheet',
'application/vnd.oasis.opendocument.spreadsheet-template',
'image/svg+xml',
'application/x-blender'
]

ACCEPT_FILE_TYPES = IMAGE_TYPES
THUMBNAIL_SIZE = 80
EXPIRATION_TIME = 300 # seconds
IMAGEPATH = [ 'images' ]
DOCPATH = [ 'document' ]
THUMBNAILPATH = [ 'images', 'thumbnails' ]
EXPIRATION_TIME = 300 # seconds
IMAGEPATH = ['images']
DOCPATH = ['document']
THUMBNAILPATH = ['images', 'thumbnails']
# change the following to POST if DELETE isn't supported by the webserver
DELETEMETHOD="DELETE"
DELETEMETHOD = "DELETE"

mimetypes.init()

class MediaPath():

class MediaPath():

def get_all(self, media_table, linked_id, MediaType=None):
filelist = list()
curpath = self.get_mediapath(media_table, linked_id, None)
thumbpath = os.path.join( curpath, 'thumbnails')
thumbpath = os.path.join(curpath, 'thumbnails')
if not os.path.isdir(curpath) or not os.path.isdir(thumbpath):
return list()
for f in os.listdir(curpath):
filename, ext = os.path.splitext( f )
if os.path.isdir(os.path.join(curpath,f)):
filename, ext = os.path.splitext(f)
if os.path.isdir(os.path.join(curpath, f)):
continue
if f.endswith('.type'):
continue
if f:
ress_url = '/image/%s/%d/%s' % (media_table, linked_id, f.replace(" ", "%20"))
thumb_url = '/image/%s/%d/thumbnails/%s' % (media_table, linked_id, f.replace(" ","%20"))
thumb_url = '/image/%s/%d/thumbnails/%s' % (media_table, linked_id, f.replace(" ", "%20"))
if MediaType is None:
if os.path.exists(os.path.join(thumbpath, f +".jpg")):
filelist.append((ress_url, thumb_url +".jpg"))
if os.path.exists(os.path.join(thumbpath, f + ".jpg")):
filelist.append((ress_url, thumb_url + ".jpg"))
else:
filelist.append((ress_url, thumb_url))
elif MediaType=='Image' and len( os.path.splitext(filename)[1] )==0:
elif MediaType == 'Image' and len(os.path.splitext(filename)[1]) == 0:
filelist.append((ress_url, thumb_url))
elif MediaType=='Other' and len( os.path.splitext(filename)[1] ):
elif MediaType == 'Other' and len(os.path.splitext(filename)[1]):
filelist.append((ress_url, thumb_url))
return filelist


def get_list(self, media_table, linked_id, MediaType=None):
filelist = list()
curpath = self.get_mediapath(media_table, linked_id, None)
if not os.path.isdir(curpath):
return list()
for f in os.listdir(curpath):
if os.path.isdir(os.path.join(curpath,f)):
if os.path.isdir(os.path.join(curpath, f)):
continue
if f.endswith('.type'):
continue
if f:
filename, ext = os.path.splitext( f )
tmpurl = '/image/%s/%d/%s' % (media_table, linked_id, f.replace(" ","%20"))
filename, ext = os.path.splitext(f)
tmpurl = '/image/%s/%d/%s' % (media_table, linked_id, f.replace(" ", "%20"))
if MediaType is None:
filelist.append(tmpurl)
elif MediaType=='Image' and ext.lower() in ['.gif','.jpg','.png','.svg','.jpeg']:
elif MediaType == 'Image' and ext.lower() in ['.gif', '.jpg', '.png', '.svg', '.jpeg']:
filelist.append(tmpurl)
elif MediaType=='Other' and ext.lower() not in ['.gif','.jpg','.png','.svg','.jpeg']:
elif MediaType == 'Other' and ext.lower() not in ['.gif', '.jpg', '.png', '.svg', '.jpeg']:
filelist.append(tmpurl)
return filelist
def get_thumb(self, media_table, linked_id, MediaType=None):
filelist = list()
curpath = self.get_mediapath(media_table, linked_id, None)
curpath = os.path.join( curpath, 'thumbnails')
curpath = os.path.join(curpath, 'thumbnails')
if not os.path.isdir(curpath):
return list()
for f in os.listdir(curpath):
filename, ext = os.path.splitext( f )
if os.path.isdir(os.path.join(curpath,f)):
filename, ext = os.path.splitext(f)
if os.path.isdir(os.path.join(curpath, f)):
continue
if f.endswith('.type'):
continue
if f:
tmpurl = '/image/%s/%d/thumbnails/%s' % (media_table, linked_id, f.replace(" ","%20"))
tmpurl = '/image/%s/%d/thumbnails/%s' % (media_table, linked_id, f.replace(" ", "%20"))
if MediaType is None:
filelist.append(tmpurl)
elif MediaType=='Image' and len( os.path.splitext(filename)[1] )==0:
elif MediaType == 'Image' and len(os.path.splitext(filename)[1]) == 0:
filelist.append(tmpurl)
elif MediaType=='Other' and len( os.path.splitext(filename)[1] ):
elif MediaType == 'Other' and len(os.path.splitext(filename)[1]):
filelist.append(tmpurl)
return filelist
return filelist

def move_mediapath(self, media_table, from_id, to_id):
"""
@@ -126,8 +127,8 @@ class MediaPath():
:return: Error if any
"""
if media_table in ['tiers', 'place', 'salle', 'users']:
src = IMAGEPATH + [ media_table, from_id ]
dst = IMAGEPATH + [ media_table, to_id ]
src = IMAGEPATH + [media_table, from_id]
dst = IMAGEPATH + [media_table, to_id]
else:
raise RuntimeError("Sorry, Media '%s' not supported yet for move." % media_table)

@@ -153,51 +154,51 @@ class MediaPath():
linked_id = str(linked_id)
if media_table in ['tiers', 'place', 'salle']:
# Retrieve Slug
if media_table=='tiers':
if media_table == 'tiers':
slug = Tiers.by_id(linked_id).slug
if media_table=='place':
if media_table == 'place':
slug = Place.by_id(linked_id).slug or slugify(Place.by_id(linked_id).name)
if media_table=='salle':
if media_table == 'salle':
slug = SallePhy.by_id(linked_id).slug
p = IMAGEPATH + [ media_table, slug ]
elif media_table=='presse':
p = IMAGEPATH + [media_table, slug]
elif media_table == 'presse':
# Use Year in linked_id
p = IMAGEPATH + [ media_table, linked_id ]
elif media_table=='tasks':
p = IMAGEPATH + [media_table, linked_id]
elif media_table == 'tasks':
# Use Current Year
p = IMAGEPATH + [ str(CurrentYear), media_table, linked_id ]
elif media_table=='poles':
p = IMAGEPATH + [str(CurrentYear), media_table, linked_id]
elif media_table == 'poles':
# Use Current Year
p = IMAGEPATH + [ str(CurrentYear), media_table, linked_id ]
p = IMAGEPATH + [str(CurrentYear), media_table, linked_id]
elif media_table in ['RIB', 'Justif']:
slug = User.by_id(linked_id).slug
p = IMAGEPATH + ['users', slug , media_table ]
p = IMAGEPATH + ['users', slug, media_table]
elif media_table in ['users', 'badge']:
user = User.by_id(linked_id)
if not user:
raise HTTPNotFound()
else:
slug = user.slug
p = IMAGEPATH + [media_table, slug ]
elif media_table=='event':
p = IMAGEPATH + [media_table, slug]
elif media_table == 'event':
ev = Event.by_id(linked_id)
slug = ev.slug
year = ev.for_year
p = IMAGEPATH + ['event', str(year), slug ]
p = IMAGEPATH + ['event', str(year), slug]

if name:
p += [ name ]
p += [name]
TargetPath = os.path.join('jm2l/upload', *p)
if not os.path.isdir(os.path.dirname(TargetPath)):
try:
os.makedirs(os.path.dirname(TargetPath))
except OSError, e:
except OSError as e:
if e.errno != 17:
raise e
return os.path.join('jm2l/upload', *p)
return os.path.join('jm2l/upload', *p)

def ExtMimeIcon(self, mime):
if mime=='application/pdf':
if mime == 'application/pdf':
return "/img/PDF.png"

def check_blend_file(self, fileobj):
@@ -217,12 +218,12 @@ class MediaPath():
fileobj.seek(0)

# Check if the binary file is a blender file
if ( mimetype == "application/octet-stream" or mimetype == "application/x-gzip" ) and self.check_blend_file(fileobj):
if (mimetype == "application/octet-stream" or mimetype == "application/x-gzip") and self.check_blend_file(
fileobj):
return "application/x-blender", True
else:
return mimetype, False


def get_mimetype(self, name):
""" This function return the mime-type based on .type file """
try:
@@ -232,6 +233,7 @@ class MediaPath():
except IOError:
return None


@view_defaults(route_name='media_upload')
class MediaUpload(MediaPath):

@@ -256,17 +258,17 @@ class MediaUpload(MediaPath):
# Try to determine mime type from content uploaded
found_mime = magic.from_buffer(filecontent.read(1024), mime=True)
filecontent.seek(0)
# Do a special statement for specific detected mime type
if found_mime in ["application/octet-stream", "application/x-gzip"]:
# Lets see if it's a bender file
if self.check_blend_file(filecontent):
found_mime = "application/x-blender"
# MonKey Patch of content type
result['type'] = found_mime
# Reject mime type that don't match
if found_mime!=result['type']:
result['type'] = found_mime
# Reject mime type that don't match
if found_mime != result['type']:
result['error'] = 'L\'extension du fichier ne correspond pas à son contenu - '
result['error'] += "( %s vs %s )" % (found_mime, result['type'])
return False
@@ -281,7 +283,7 @@ class MediaUpload(MediaPath):
result['error'] = 'le fichier est trop petit'
elif result['size'] > MAX_FILE_SIZE:
result['error'] = 'le fichier est trop voluminueux'
#elif not ACCEPT_FILE_TYPES.match(file['type']):
# elif not ACCEPT_FILE_TYPES.match(file['type']):
# file['error'] = u'les type de fichiers acceptés sont png, jpg et gif'
else:
return True
@@ -289,80 +291,80 @@ class MediaUpload(MediaPath):
return False

def get_file_size(self, fileobj):
fileobj.seek(0, 2) # Seek to the end of the file
size = fileobj.tell() # Get the position of EOF
fileobj.seek(0) # Reset the file position to the beginning
fileobj.seek(0, 2) # Seek to the end of the file
size = fileobj.tell() # Get the position of EOF
fileobj.seek(0) # Reset the file position to the beginning
return size

def thumbnailurl(self,name):
return self.request.route_url('media_view',name='thumbnails',
media_table=self.media_table,
uid=self.linked_id) + '/' + name
def thumbnailurl(self, name):
return self.request.route_url('media_view', name='thumbnails',
media_table=self.media_table,
uid=self.linked_id) + '/' + name

def thumbnailpath(self,name):
def thumbnailpath(self, name):
origin = self.mediapath(name)
TargetPath = os.path.join( os.path.dirname(origin), 'thumbnails', name)
TargetPath = os.path.join(os.path.dirname(origin), 'thumbnails', name)
if not os.path.isdir(os.path.dirname(TargetPath)):
os.makedirs(os.path.dirname(TargetPath))
os.makedirs(os.path.dirname(TargetPath))
return TargetPath

def createthumbnail(self, filename):
image = Image.open( self.mediapath(filename) )
image = Image.open(self.mediapath(filename))
image.thumbnail((THUMBNAIL_SIZE, THUMBNAIL_SIZE), Image.ANTIALIAS)
timage = Image.new('RGBA', (THUMBNAIL_SIZE, THUMBNAIL_SIZE), (255, 255, 255, 0))
timage.paste(
image,
((THUMBNAIL_SIZE - image.size[0]) / 2, (THUMBNAIL_SIZE - image.size[1]) / 2))
TargetFileName = self.thumbnailpath(filename)
timage.save( TargetFileName )
return self.thumbnailurl( os.path.basename(TargetFileName) )
timage.save(TargetFileName)
return self.thumbnailurl(os.path.basename(TargetFileName))

def pdfthumbnail(self, filename):
TargetFileName = self.thumbnailpath(filename)
Command = ["convert","./%s[0]" % self.mediapath(filename),"./%s_.jpg" % TargetFileName]
Command = ["convert", "./%s[0]" % self.mediapath(filename), "./%s_.jpg" % TargetFileName]
Result = subprocess.call(Command)
if Result==0:
image = Image.open( TargetFileName+"_.jpg" )
pdf_indicator = Image.open( "jm2l/static/img/PDF_Thumb_Stamp.png" )
if Result == 0:
image = Image.open(TargetFileName + "_.jpg")
pdf_indicator = Image.open("jm2l/static/img/PDF_Thumb_Stamp.png")
image.thumbnail((THUMBNAIL_SIZE, THUMBNAIL_SIZE), Image.ANTIALIAS)
timage = Image.new('RGBA', (THUMBNAIL_SIZE, THUMBNAIL_SIZE), (255, 255, 255, 0))
# Add thumbnail
timage.paste(
image,
image,
((THUMBNAIL_SIZE - image.size[0]) / 2, (THUMBNAIL_SIZE - image.size[1]) / 2))
# Stamp with PDF file type
timage.paste(
pdf_indicator,
(timage.size[0]-30, timage.size[1]-30),
(timage.size[0] - 30, timage.size[1] - 30),
pdf_indicator,
)
timage.convert('RGB').save( TargetFileName+".jpg", 'JPEG')
os.unlink(TargetFileName+"_.jpg")
return self.thumbnailurl( os.path.basename(TargetFileName+".jpg") )
)
timage.convert('RGB').save(TargetFileName + ".jpg", 'JPEG')
os.unlink(TargetFileName + "_.jpg")
return self.thumbnailurl(os.path.basename(TargetFileName + ".jpg"))
return self.ExtMimeIcon('application/pdf')

def svgthumbnail(self, filename):
TargetFileName = self.thumbnailpath(filename)
Command = ["convert","./%s[0]" % self.mediapath(filename),"./%s_.jpg" % TargetFileName]
Command = ["convert", "./%s[0]" % self.mediapath(filename), "./%s_.jpg" % TargetFileName]
Result = subprocess.call(Command)
if Result==0:
image = Image.open( TargetFileName+"_.jpg" )
pdf_indicator = Image.open( "jm2l/static/img/svg-icon.png" )
if Result == 0:
image = Image.open(TargetFileName + "_.jpg")
pdf_indicator = Image.open("jm2l/static/img/svg-icon.png")
image.thumbnail((THUMBNAIL_SIZE, THUMBNAIL_SIZE), Image.ANTIALIAS)
timage = Image.new('RGBA', (THUMBNAIL_SIZE, THUMBNAIL_SIZE), (255, 255, 255, 0))
# Add thumbnail
timage.paste(
image,
image,
((THUMBNAIL_SIZE - image.size[0]) / 2, (THUMBNAIL_SIZE - image.size[1]) / 2))
# Stamp with PDF file type
timage.paste(
pdf_indicator,
(timage.size[0]-30, timage.size[1]-30),
(timage.size[0] - 30, timage.size[1] - 30),
pdf_indicator,
)
timage.convert('RGB').save( TargetFileName+".jpg", 'JPEG')
os.unlink(TargetFileName+"_.jpg")
return self.thumbnailurl( os.path.basename(TargetFileName+".jpg") )
)
timage.convert('RGB').save(TargetFileName + ".jpg", 'JPEG')
os.unlink(TargetFileName + "_.jpg")
return self.thumbnailurl(os.path.basename(TargetFileName + ".jpg"))
return self.ExtMimeIcon('image/svg+xml')

def docthumbnail(self, filename):
@@ -370,29 +372,30 @@ class MediaUpload(MediaPath):
# let's take the thumbnail generated inside the document
Command = ["unzip", "-p", self.mediapath(filename), "Thumbnails/thumbnail.png"]
ThumbBytes = subprocess.check_output(Command)
image = Image.open( StringIO.StringIO(ThumbBytes) )
image = Image.open(StringIO.StringIO(ThumbBytes))
image.thumbnail((THUMBNAIL_SIZE, THUMBNAIL_SIZE), Image.ANTIALIAS)
# Use the correct stamp
f, ext = os.path.splitext( filename )
istamp = [ ('Writer','odt'),
('Impress','odp'),
('Calc','ods'),
('Draw','odg')]
stampfilename = filter(lambda (x,y): ext.endswith(y), istamp)
stamp = Image.open( "jm2l/static/img/%s-icon.png" % stampfilename[0][0])
f, ext = os.path.splitext(filename)
istamp = [('Writer', 'odt'),
('Impress', 'odp'),
('Calc', 'ods'),
('Draw', 'odg')]
stampfilename = filter(lambda x, y: ext.endswith(y), istamp)
stamp = Image.open("jm2l/static/img/%s-icon.png" % stampfilename[0][0])

timage = Image.new('RGBA', (THUMBNAIL_SIZE, THUMBNAIL_SIZE), (255, 255, 255, 0))
# Add thumbnail
timage.paste(
image,
image,
((THUMBNAIL_SIZE - image.size[0]) / 2, (THUMBNAIL_SIZE - image.size[1]) / 2))
# Stamp with PDF file type
timage.paste(
stamp,
(timage.size[0]-30, timage.size[1]-30),
(timage.size[0] - 30, timage.size[1] - 30),
stamp,
)
timage.convert('RGB').save( TargetFileName+".jpg", 'JPEG')
return self.thumbnailurl( os.path.basename(TargetFileName+".jpg") )
)
timage.convert('RGB').save(TargetFileName + ".jpg", 'JPEG')
return self.thumbnailurl(os.path.basename(TargetFileName + ".jpg"))

def blendthumbnail(self, filename):
blendfile = self.mediapath(filename)
@@ -400,18 +403,18 @@ class MediaUpload(MediaPath):
if 0:
head = fileobj.read(12)
fileobj.seek(0)
if head[:2] == b'\x1f\x8b': # gzip magic
import zlib
head = zlib.decompress(fileobj.read(), 31)[:12]
fileobj.seek(0)
fileobj.seek(0)
buf, width, height = blend_extract_thumb(blendfile)
if buf:
png = write_png(buf, width, height)
TargetFileName = self.thumbnailpath(filename)
image = Image.open(StringIO.StringIO(png))
blender_indicator = Image.open( "jm2l/static/img/Blender_Thumb_Stamp.png" )
blender_indicator = Image.open("jm2l/static/img/Blender_Thumb_Stamp.png")
image.thumbnail((THUMBNAIL_SIZE, THUMBNAIL_SIZE), Image.ANTIALIAS)
timage = Image.new('RGBA', (THUMBNAIL_SIZE, THUMBNAIL_SIZE), (255, 255, 255, 0))
# Add thumbnail
@@ -421,24 +424,24 @@ class MediaUpload(MediaPath):
# Stamp with Blender file type
timage.paste(
blender_indicator,
(timage.size[0]-30, timage.size[1]-30),
(timage.size[0] - 30, timage.size[1] - 30),
blender_indicator,
)
timage.save( TargetFileName+".png")
return self.thumbnailurl( os.path.basename(TargetFileName+".png") )
)
timage.save(TargetFileName + ".png")
return self.thumbnailurl(os.path.basename(TargetFileName + ".png"))
return self.ExtMimeIcon('application/x-blender')

def fileinfo(self,name):
filename = self.mediapath(name)
def fileinfo(self, name):
filename = self.mediapath(name)
f, ext = os.path.splitext(name)
if ext!='.type' and os.path.isfile(filename):
if ext != '.type' and os.path.isfile(filename):
info = {}
info['name'] = name
info['size'] = os.path.getsize(filename)
info['url'] = self.request.route_url('media_view',
name=name,
media_table=self.media_table,
uid=self.linked_id)
name=name,
media_table=self.media_table,
uid=self.linked_id)

mime = self.get_mimetype(name)
if IMAGE_TYPES.match(mime):
@@ -448,8 +451,8 @@ class MediaUpload(MediaPath):
thumbext = ".jpg"
if mime == "application/x-blender":
thumbext = ".png"
if os.path.exists( thumb + thumbext ):
info['thumbnailUrl'] = self.thumbnailurl(name)+thumbext
if os.path.exists(thumb + thumbext):
info['thumbnailUrl'] = self.thumbnailurl(name) + thumbext
else:
info['thumbnailUrl'] = self.ExtMimeIcon(mime)
else:
@@ -457,10 +460,10 @@ class MediaUpload(MediaPath):
if not self.display_only:
info['deleteType'] = DELETEMETHOD
info['deleteUrl'] = self.request.route_url('media_upload',
sep='',
name='',
media_table=self.media_table,
uid=self.linked_id) + '/' + name
sep='',
name='',
media_table=self.media_table,
uid=self.linked_id) + '/' + name
if DELETEMETHOD != 'DELETE':
info['deleteUrl'] += '&_method=DELETE'
return info
@@ -488,7 +491,7 @@ class MediaUpload(MediaPath):
n = self.fileinfo(f)
if n:
filelist.append(n)
return { "files":filelist }
return {"files": filelist}

@view_config(request_method='DELETE', xhr=True, accept="application/json", renderer='json')
def delete(self):
@@ -498,32 +501,32 @@ class MediaUpload(MediaPath):
except IOError:
pass
except OSError:
pass
pass
try:
os.remove(self.thumbnailpath(filename))
except IOError:
pass
except OSError:
except OSError:
pass
try:
os.remove(self.thumbnailpath(filename+".jpg"))
os.remove(self.thumbnailpath(filename + ".jpg"))
except IOError:
pass
except OSError:
pass
except OSError:
pass
try:
os.remove(self.mediapath(filename))
except IOError:
return False
return True
@view_config(request_method='POST', xhr=True, accept="application/json", renderer='json')
def post(self):
if self.request.matchdict.get('_method') == "DELETE":
return self.delete()
results = []
for name, fieldStorage in self.request.POST.items():
if isinstance(fieldStorage,unicode):
if isinstance(fieldStorage, unicode):
continue
result = {}
result['name'] = os.path.basename(fieldStorage.filename)
@@ -531,63 +534,64 @@ class MediaUpload(MediaPath):
result['size'] = self.get_file_size(fieldStorage.file)

if self.validate(result, fieldStorage.file):
filename, file_extension = os.path.splitext( result['name'] )
local_filename = slugify( filename ) + file_extension
filename, file_extension = os.path.splitext(result['name'])
local_filename = slugify(filename) + file_extension
# Keep mime-type in .type file
with open( self.mediapath( local_filename ) + '.type', 'w') as f:
with open(self.mediapath(local_filename) + '.type', 'w') as f:
f.write(result['type'])
# Store uploaded file
fieldStorage.file.seek(0)
with open( self.mediapath( local_filename ), 'wb') as f:
shutil.copyfileobj( fieldStorage.file , f)
with open(self.mediapath(local_filename), 'wb') as f:
shutil.copyfileobj(fieldStorage.file, f)

if re.match(IMAGE_TYPES, result['type']):
result['thumbnailUrl'] = self.createthumbnail(local_filename)
elif result['type']=='application/pdf':
elif result['type'] == 'application/pdf':
result['thumbnailUrl'] = self.pdfthumbnail(local_filename)
elif result['type']=='image/svg+xml':
elif result['type'] == 'image/svg+xml':
result['thumbnailUrl'] = self.svgthumbnail(local_filename)
elif result['type'].startswith('application/vnd'):
result['thumbnailUrl'] = self.docthumbnail(local_filename)
elif result['type']=='application/x-blender':
elif result['type'] == 'application/x-blender':
result['thumbnailUrl'] = self.blendthumbnail(local_filename)
else:
result['thumbnailUrl'] = self.ExtMimeIcon(result['type'])

result['deleteType'] = DELETEMETHOD
result['deleteUrl'] = self.request.route_url('media_upload',
sep='',
name='',
media_table=self.media_table,
uid=self.linked_id) + '/' + local_filename
sep='',
name='',
media_table=self.media_table,
uid=self.linked_id) + '/' + local_filename
result['url'] = self.request.route_url('media_view',
media_table=self.media_table,
uid=self.linked_id,
name=local_filename)
media_table=self.media_table,
uid=self.linked_id,
name=local_filename)
if DELETEMETHOD != 'DELETE':
result['deleteUrl'] += '&_method=DELETE'
results.append(result)
return {"files":results}
return {"files": results}


@view_defaults(route_name='media_view')
class MediaView(MediaPath):

def __init__(self,request):
def __init__(self, request):
self.request = request
self.media_table = self.request.matchdict.get('media_table')
self.linked_id = self.request.matchdict.get('uid')

def mediapath(self,name):
def mediapath(self, name):
return self.get_mediapath(self.media_table, self.linked_id, name)
@view_config(request_method='GET', http_cache = (EXPIRATION_TIME, {'public':True}))
@view_config(request_method='GET', http_cache=(EXPIRATION_TIME, {'public': True}))
def get(self):
name = self.request.matchdict.get('name')
self.request.response.content_type = self.get_mimetype(name)

try:
self.request.response.body_file = open( self.mediapath(name), 'rb', 10000)
self.request.response.body_file = open(self.mediapath(name), 'rb', 10000)
except IOError:
raise NotFound
return self.request.response


+ 798
- 729
jm2l/views.py
File diff suppressed because it is too large
View File


+ 3
- 2
setup.py View File

@@ -28,13 +28,14 @@ requires = [
'python-magic',
'Pillow',
'pyramid_exclog',
'repoze.sendmail==4.1',
'repoze.sendmail',
'pyramid_mailer',
'apscheduler',
'qrcode',
'reportlab',
'passlib',
'argon2_cffi'
'argon2_cffi',
'paginate'
]

setup(name='JM2L',


Loading…
Cancel
Save