Browse Source

Fixing python3 issues

feature/python-3-migration
tr4ck3ur des JM2L 4 years ago
parent
commit
2b3e8116d5
10 changed files with 313 additions and 292 deletions
  1. +1
    -1
      README.txt
  2. +0
    -1
      development.ini
  3. +16
    -13
      jm2l/__init__.py
  4. +81
    -82
      jm2l/badge.py
  5. +4
    -4
      jm2l/captcha.py
  6. +54
    -41
      jm2l/forms.py
  7. +51
    -46
      jm2l/helpers.py
  8. +97
    -100
      jm2l/to_print.py
  9. +4
    -2
      jm2l/views.py
  10. +5
    -2
      setup.py

+ 1
- 1
README.txt View File

@@ -38,7 +38,7 @@ If no error occurs, the webserver should be available on http://localhost:8080/
Enjoy !


sudo apt install virtualenv git python3-virtualenv
sudo apt install virtualenv git python3-virtualenv imagemagick

sudo mkdir -p /srv/jm2l
cd /srv/jm2l/


+ 0
- 1
development.ini View File

@@ -15,7 +15,6 @@ pyramid.debug_notfound = false
pyramid.debug_routematch = false
pyramid.default_locale_name = en
pyramid.includes =
pyramid_mailer.testing
pyramid_debugtoolbar
pyramid_tm
pyramid_mako


+ 16
- 13
jm2l/__init__.py View File

@@ -30,31 +30,31 @@ def add_renderer_globals(event):
event['CurrentYear'] = CurrentYear


# @sched.scheduled_job('cron', day_of_week='sun', hour=22, minute=07)
# @sched.scheduled_job('cron', day_of_week='sun', hour=22, minute=7)
def mailer_tasks(config):
# Send the Welcome Mail
mailer = config.registry['mailer']
Contact = DBSession.query(User).filter(User.uid == 1).one()
contact = DBSession.query(User).filter(User.uid == 1).one()
request = Request.blank('/', base_url='http://jm2l.linux-azur.org')
request.registry = config.registry
for StaffUser in DBSession.query(User).filter(User.Staff == True):
for staff_user in DBSession.query(User).filter(User.Staff is True):
# Skip mail to contact
if StaffUser == Contact:
if staff_user == contact:
continue
# Skip those that have no task assigned
if len(filter(lambda k: not k.closed, StaffUser.task_assoc)) == 0:
if len(filter(lambda k: not k.closed, staff_user.task_assoc)) == 0:
continue

# Prepare Plain Text Message :
Mail_template = Template(filename='jm2l/templates/mail_plain.mako')
mail_plain = Mail_template.render(request=request, User=StaffUser, Contact=Contact, action="Tasks")
mail_template = Template(filename='jm2l/templates/mail_plain.mako')
mail_plain = mail_template.render(request=request, User=staff_user, Contact=contact, action="Tasks")
# Prepare HTML Message :
Mail_template = Template(filename='jm2l/templates/mail_html.mako')
mail_html = Mail_template.render(request=request, User=StaffUser, Contact=Contact, action="Tasks")
mail_template = Template(filename='jm2l/templates/mail_html.mako')
mail_html = mail_template.render(request=request, User=staff_user, Contact=contact, action="Tasks")
# Prepare Message
message = Message(subject="[JM2L] Le mail de rappel pour les JM2L !",
sender="contact@jm2l.linux-azur.org",
recipients=[StaffUser.mail],
recipients=[staff_user.mail],
body=mail_plain, html=mail_html)

message.add_bcc("spam@style-python.fr")
@@ -81,8 +81,11 @@ def main(global_config, **settings):
authentication_policy=authentication_policy,
authorization_policy=authorization_policy
)
#config.include('pyramid_mailer')
config.include('pyramid_mailer.debug')
config.add_subscriber(add_renderer_globals, BeforeRender)
config.registry['mailer'] = mailer_factory_from_settings(settings)
print(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])
@@ -154,7 +157,7 @@ def main(global_config, **settings):
config.add_route('edit_event', r'/MesJM2L/{year:\d+}/{intervention:[\s\w]+}{sep:/*}{event_id:([\w-]+)?}')
config.add_route('delete_event', r'/MesJM2L/{year:\d+}/{intervention:[\s\w]+}{sep:/*}{event_id:([\w-]+)?}/delete')

## Entities
# Entities
config.add_route('entities', '/entities') # {sep:/*}{Nature:\w+?}')
config.add_route('add_entity', '/entity')
config.add_route('delete_entity', r'/entity/{entity_id:(\d+)}/delete')
@@ -162,7 +165,7 @@ def main(global_config, **settings):
config.add_route('edit_entity', r'/entity/{tiers_type:(\w+)}/{entity_id:([\w-]+)}/edit')
config.add_route('edit_entity_cat', '/categorie/entity')

## Users
# Users
config.add_route('pict_user', '/user_picture')
config.add_route('show_user', r'/user/{user_slug:([\w-]+)?}')
config.add_route('badge_user', r'/user/{user_slug:([\w-]+)?}/badge')


+ 81
- 82
jm2l/badge.py View File

@@ -6,6 +6,7 @@ try:
from StringIO import StringIO
except ImportError:
from io import StringIO
import io
from pyramid.view import view_config
from .models import DBSession, User
from reportlab.pdfgen import canvas
@@ -25,38 +26,38 @@ ICONSIZE = 10 * mm


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.textLines("JM2L")
canvas.drawText(logoobject)
yearobject = canvas.beginText()
yearobject.setFont("Helvetica-Bold", 10)
yearobject.setFillColorRGB(1, 1, 1)
yearobject.setTextRenderMode(0)
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)):
Border = 0
OffX, OffY = Offset
if StartPos is None:
StartPos = (30 * mm, 2)
StartX, StartY = StartPos
MaxX, MaxY = 34 * mm, 18 * mm
off_x, off_y = Offset
logo_object = canvas.beginText()
logo_object.setFont('Logo', 32)
logo_object.setFillColorRGB(.83, 0, .33)
logo_object.setTextOrigin(off_x + 5, off_y + 17)
logo_object.textLines("JM2L")
canvas.drawText(logo_object)
year_object = canvas.beginText()
year_object.setFont("Helvetica-Bold", 10)
year_object.setFillColorRGB(1, 1, 1)
year_object.setTextRenderMode(0)
year_object.setTextOrigin(off_x + 12, off_y + 35)
year_object.setWordSpace(13)
year_object.textLines(" ".join(str(CurrentYear)))
canvas.drawText(year_object)
def Tiers_Logo(canvas, DispUser, start_pos=None, Offset=(0, 0)):
border = 0
off_x, off_y = Offset
if start_pos is None:
start_pos = (30 * mm, 2)
start_x, start_y = start_pos
max_x, max_y = 34 * mm, 18 * mm
num = 0
canvas.setStrokeColorRGB(0.5, 0.5, 0.5)
Logos = list()
list_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])
list_logos.append(thumb.ThumbLinks[:3])
# list_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)}
@@ -75,25 +76,25 @@ def Tiers_Logo(canvas, DispUser, StartPos=None, Offset=(0, 0)):
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
# canvas.roundRect(start_x, start_y, max_x, max_y, radius=2, stroke=True)
for tiers in list_logos:
file_name = tiers.ThumbLinks.pop().split("/")[-1]
image_path = "jm2l/upload/images/tiers/%s/%s" % (tiers.slug, file_name)
pos_x = off_x + start_x + DicPos[len(list_logos)][num][0] * max_x - (ICONSIZE + border) / 2
pos_y = off_y + start_y + DicPos[len(list_logos)][num][1] * max_y - (ICONSIZE + border) / 2
canvas.setLineWidth(.1)
if len(Logos) > 1:
if len(list_logos) > 1:
size = ICONSIZE
else:
size = ICONSIZE * 1.5
canvas.drawImage(ImagePath,
PosX, PosY, size, size,
canvas.drawImage(image_path,
pos_x, pos_y, size, size,
preserveAspectRatio=True,
anchor='c',
mask='auto'
)
# draw icon border
# canvas.roundRect(PosX, PosY, ICONSIZE, ICONSIZE, radius=2, stroke=True)
# canvas.roundRect(pos_x, pos_y, ICONSIZE, ICONSIZE, radius=2, stroke=True)
num += 1


@@ -114,37 +115,37 @@ def QRCode(DispUser):
def one_badge(c, DispUser, Offset=(0, 0)):
# Logo on Top
JM2L_Logo(c, Offset)
OffX, OffY = Offset
off_x, off_y = Offset

c.rect(OffX - 3, OffY - 3, WIDTH + 6, HEIGHT + 6, fill=0, stroke=1)
c.rect(off_x - 3, off_y - 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.rect(off_x - 3, off_y + 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(off_x + WIDTH / 2, off_y + 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.rect(off_x - 3, off_y + 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(off_x + WIDTH / 2, off_y + 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.rect(off_x - 3, off_y + 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(off_x + WIDTH / 2, off_y + 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.rect(off_x - 3, off_y + 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(off_x + WIDTH / 2, off_y + HEIGHT - 24, "Visiteur")

c.restoreState()

@@ -154,25 +155,25 @@ def one_badge(c, DispUser, Offset=(0, 0)):
# Feed Name and SurName
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.drawCentredString(off_x + WIDTH / 2, off_y + 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(off_x + WIDTH / 2, off_y + HEIGHT / 2 - 8 * mm, "%s" % DispUser.nom)
else:
c.drawCentredString(OffX + WIDTH / 2, OffY + HEIGHT / 2 + 4 * mm, "%s" % DispUser.prenom)
c.drawCentredString(off_x + WIDTH / 2, off_y + 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(off_x + WIDTH / 2, off_y + 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(off_x + WIDTH / 2, off_y + 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)
c.drawCentredString(off_x + WIDTH / 2, off_y + 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, \
c.drawInlineImage(QRCode(DispUser),
off_x + WIDTH - 20 * mm - 5, off_y + 5,
20 * mm, 20 * mm,
preserveAspectRatio=True,
anchor='s')

Tiers_Logo(c, DispUser, None, Offset)
@@ -192,14 +193,14 @@ def badge_user(request):
# Ok let's generate a PDF Badge

# Register LiberationMono font
ttfFile = "jm2l/static/fonts/LiberationMono-Regular.ttf"
pdfmetrics.registerFont(TTFont("Liberation", ttfFile))
ttf_file = "jm2l/static/fonts/LiberationMono-Regular.ttf"
pdfmetrics.registerFont(TTFont("Liberation", ttf_file))
#  Import font
ttfFile_Logo = "jm2l/static/fonts/PWTinselLetters.ttf"
pdfmetrics.registerFont(TTFont("Logo", ttfFile_Logo))
ttf_file_logo = "jm2l/static/fonts/PWTinselLetters.ttf"
pdfmetrics.registerFont(TTFont("Logo", ttf_file_logo))

pdf = StringIO()
out_img = StringIO()
pdf = io.BytesIO()
out_img = io.BytesIO()

c = canvas.Canvas(pdf, pagesize=(WIDTH, HEIGHT))
c.translate(mm, mm)
@@ -211,23 +212,21 @@ def badge_user(request):
c.saveState()

one_badge(c, DispUser)
OutPDF = MediaPath().get_mediapath("badge", DispUser.uid, 'badge.pdf')
out_pdf = MediaPath().get_mediapath("badge", DispUser.uid, 'badge.pdf')
c.showPage()
c._filename = OutPDF
c.save()
pdf.seek(0)
if isoutpng:

OutPNG = MediaPath().get_mediapath("badge", DispUser.uid, 'badge.png')
out_png = MediaPath().get_mediapath("badge", DispUser.uid, 'badge.png')
#  Let's generate a png file for website
with open("./%s" % OutPDF, 'wb') as pdff:
pdff.write(bytes(pdf.read(), 'utf8')) # .encode('utf8'))
with open("./%s" % out_pdf, 'wb') as pdff:
pdff.write(pdf.read())

Command = ["convert", "-density", "150x150", OutPDF, OutPNG]
Command = ["convert", "-density", "150x150", out_pdf, out_png]
subprocess.call(Command)

with open("./%s" % OutPNG, 'r') as pngfile:
out_img.write(bytes(pngfile.read(), 'utf8')) # bytes(pngfile.read(), "utf8"))
with open("./%s" % out_png, 'rb') as pngfile:
out_img.write(pngfile.read()) # pngfile.read(), "utf8"))

out_img.seek(0)
return Response(app_iter=out_img, content_type='image/png')
@@ -246,13 +245,13 @@ def planche_badge(request):
# .filter(User_Event.year_uid == year)

# Register LiberationMono font
ttfFile = "jm2l/static/fonts/LiberationMono-Regular.ttf"
pdfmetrics.registerFont(TTFont("Liberation", ttfFile))
ttf_file = "jm2l/static/fonts/LiberationMono-Regular.ttf"
pdfmetrics.registerFont(TTFont("Liberation", ttf_file))
#  Import font
ttfFile_Logo = "jm2l/static/fonts/PWTinselLetters.ttf"
pdfmetrics.registerFont(TTFont("Logo", ttfFile_Logo))
ttf_file_logo = "jm2l/static/fonts/PWTinselLetters.ttf"
pdfmetrics.registerFont(TTFont("Logo", ttf_file_logo))

pdf = StringIO.StringIO()
pdf = io.BytesIO()

FULLWIDTH = 210 * mm
FULLHEIGHT = 297 * mm
@@ -264,11 +263,11 @@ def planche_badge(request):
c.setCreator("linux-azur.org")
c.setTitle("Badge")
t = 0
ListUser = filter(lambda x: x.is_Intervenant or x.Staff or x.is_crew, Users)
for num, DispUser in enumerate(ListUser):
list_user = filter(lambda x: x.is_Intervenant or x.Staff or x.is_crew, Users)
for num, disp_user in enumerate(list_user):
c.saveState()
Offsets = (((num - t) % 2) * (WIDTH + 40) + 40, ((num - t) / 2) * (HEIGHT + 25) + 40)
one_badge(c, DispUser, Offsets)
offsets = (((num - t) % 2) * (WIDTH + 40) + 40, int(((num - t) / 2)) * (HEIGHT + 25) + 40)
one_badge(c, disp_user, offsets)
if num % 8 == 7:
t = num + 1
c.showPage()


+ 4
- 4
jm2l/captcha.py View File

@@ -115,8 +115,8 @@ class _PyCaptcha_SineWarp(_PyCaptcha_WarpBase):

@view_config(route_name='captcha')
def DoCaptcha(request):
ImgSize = (230, 100)
work_img = Image.new('RGBA', ImgSize, (255, 255, 255, 0))
img_size = (230, 100)
work_img = Image.new('RGBA', img_size, (255, 255, 255, 0))
Xmax, Ymax = work_img.size
# Write something on it
draw = ImageDraw.Draw(work_img)
@@ -129,7 +129,7 @@ def DoCaptcha(request):
# Choose a word for captcha
text = random.choice(TabMots)
Xt, Yt = font.getsize(text)
OrX, OrY = (ImgSize[0] - Xt) / 2, (ImgSize[1] - Yt) / 2
OrX, OrY = (img_size[0] - Xt) / 2, (img_size[1] - Yt) / 2
draw.text((OrX, OrY), text, font=font, fill="#000000")
# Apply a Blur
# work_img=work_img.filter(ImageFilter.BLUR)
@@ -140,7 +140,7 @@ def DoCaptcha(request):
tx, ty = (random.uniform(0, 0.0003), random.uniform(0, 0.0003))
bx, by = (random.uniform(0.5, 0.8), random.uniform(0, 0.2))
# Apply perspective to Captcha
work_img = work_img.transform(ImgSize, Image.PERSPECTIVE, (ax, bx, -25, by, ay, -10, tx, ty))
work_img = work_img.transform(img_size, Image.PERSPECTIVE, (ax, bx, -25, by, ay, -10, tx, ty))
# Apply SinWarp to Captcha
tr = Captcha_Img(Xmax, Ymax)
tr._image = work_img


+ 54
- 41
jm2l/forms.py View File

@@ -11,17 +11,20 @@ from wtforms.csrf.session import SessionCSRF
from datetime import timedelta
from jm2l.const import CurrentYear


# What about an helper function
#def strip_filter(x)
# if x is no
strip_filter = lambda x: x.strip() if x else None
def strip_filter(x):
# strip_filter = lambda x: x.strip() if x else None
if x:
return x.strip()
return None


# get random string password with letters, digits, and symbols
def get_random_string(length):
csrf_characters = string.ascii_letters + string.digits + string.punctuation
csrf = ''.join(random.choice(password_characters) for i in range(length))
return csrf
csrf = ''.join(random.choice(csrf_characters) for i in range(length))
return bytes(csrf, 'utf8')


class MyBaseForm(Form):
@@ -155,32 +158,38 @@ class ConfCreateForm(MyBaseForm):
start_time = HiddenField()
end_time = HiddenField()

start_sel = SelectField(u'Début', coerce=int,
description=u"C'est une heure indicative correspondant au mieux à vos préférences " +
u"personnelles. Vous pouvez prendre un créneau horaire déjà réservé si vous avez des contraintes "
u"particulières. L'équipe des JM2L mettra à disposition plus de salle si nécessaire. En cas de conflit," +
u"l'organisation se réserve le droit de changer la salle et l'heure avec votre accord."
)
duration = SelectField(u'Durée', coerce=int,
description=u"Précisez ici la durée de votre intervention"
)

salle_uid = SelectField(u'Salle', coerce=int,
description=u"Choisissez ici la salle en fonction "
u"du nombres de personnes potentiellement intéressé par votre intervention " +
u"l'organisation se réserve le droit de changer la salle (avec votre accord)."

)

name = StringField(u'Le nom de votre ',
[validators.DataRequired(u'Vous devez spécifier un nom pour votre intérvention'),
validators.Length(min=1, max=80, message='entre 1 et 80 car')],
filters=[strip_filter])

description = TextAreaField(u'Décrivez ici quelques détails à propos de votre intervention ',
[validators.Optional(), validators.Length(max=1000000)],
filters=[strip_filter]
)
start_sel = SelectField(
u'Début', coerce=int,
description=u"C'est une heure indicative correspondant au mieux à vos préférences "
u"personnelles. Vous pouvez prendre un créneau horaire déjà réservé si vous avez des contraintes "
u"particulières. L'équipe des JM2L mettra à disposition plus de salle si nécessaire. "
u"En cas de conflit,"
u"l'organisation se réserve le droit de changer la salle et l'heure avec votre accord."
)

duration = SelectField(
u'Durée', coerce=int,
description=u"Précisez ici la durée de votre intervention")

salle_uid = SelectField(
u'Salle', coerce=int,
description=u"Choisissez ici la salle en fonction du nombres de personnes potentiellement "
u"intéressé par votre intervention l'organisation se réserve le droit de changer"
u" la salle (avec votre accord)."
)

name = StringField(
u'Le nom de votre ',
[validators.DataRequired(u'Vous devez spécifier un nom pour votre intérvention'),
validators.Length(min=1, max=80, message='entre 1 et 80 car')],
filters=[strip_filter]
)

description = TextAreaField(
u'Décrivez ici quelques détails à propos de votre intervention ',
[validators.Optional(), validators.Length(max=1000000)],
filters=[strip_filter]
)


class ConfUpdateForm(ConfCreateForm):
@@ -223,9 +232,10 @@ class PlaceCreateForm(MyBaseForm):
filters=[strip_filter])
name = StringField('Nom Complet', [validators.Length(min=1, max=80)],
filters=[strip_filter])
gps_coord = StringField(u'Coordonnées GPS', [validators.Length(max=30),
validators.Regexp("^[0-9]+\.?[0-9]+,[0-9]+\.?[0-9]+$",
message=u"Le GPS devrait être sous la forme 43.6158372,7.0723401")],
gps_coord = StringField(u'Coordonnées GPS',
[validators.Length(max=30),
validators.Regexp("^[0-9]+\.?[0-9]+,[0-9]+\.?[0-9]+$",
message=u"Le GPS devrait être sous la forme 43.6158372,7.0723401")],
filters=[strip_filter])
adresse = TextAreaField('Adresse', [validators.Length(max=100)],
filters=[strip_filter])
@@ -600,13 +610,16 @@ class PropMForm(MyBaseForm):
message=u"doit être sous la forme HH:MM")],
filters=[strip_filter])
end_time = HiddenField()
exch_categ = SelectField(u'Catégorie de matériel', coerce=int,
description=u"Choisissez une catégorie de bien matériel"
)
description = TextAreaField(u'Ajoutez quelques mots autour du matériel que vous proposez', filters=[strip_filter],
description=u"Décrivez ici quelques détails sur le matériel que vous souhaitez "
+ u"proposer. N'hésitez pas à donner des détails."
)
exch_categ = SelectField(
u'Catégorie de matériel', coerce=int,
description=u"Choisissez une catégorie de bien matériel"
)
description = TextAreaField(
u'Ajoutez quelques mots autour du matériel que vous proposez',
filters=[strip_filter],
description=u"Décrivez ici quelques détails sur le matériel "
u"que vous souhaitez proposer. N'hésitez pas à donner des détails."
)


class UpdateAskCForm(AskCForm, UpdateExchangeForm):


+ 51
- 46
jm2l/helpers.py View File

@@ -5,6 +5,11 @@ import itertools
from jm2l.const import CurrentYear


def get_current_year():
""" This function is intended to return the year of the next edition """
return CurrentYear


class DummySejour(object):

def __init__(self, event):
@@ -29,78 +34,78 @@ class Sejour_helpers(DummySejour):
# This function return the start of the event
return self.CurrentYear

def PossibleDate(self, typedate="arrival"):
def PossibleDate(self, type_date="arrival"):
arrival, departure = False, False
TabResult = list()
if typedate == "arrival":
tab_result = list()
if type_date == "arrival":
# Let's say people should arrive until 2 day before
arrival = True
myDayRange = range(2, -1, -1)
elif typedate == "departure":
my_day_range = range(2, -1, -1)
elif type_date == "departure":
# Let's say people should go back home until 2 day after
departure = True
myDayRange = range(3)
my_day_range = range(3)
else:
return TabResult
return tab_result

if self.Sejour:
ArrDate = datetime.strftime(self.Sejour.arrival_time, "%d %B %Y")
DepDate = datetime.strftime(self.Sejour.depart_time, "%d %B %Y")
arr_date = datetime.strftime(self.Sejour.arrival_time, "%d %B %Y")
dep_date = datetime.strftime(self.Sejour.depart_time, "%d %B %Y")
else:
ArrDate = datetime.strftime(self.CurrentEventYear.start_time, "%d %B %Y")
DepDate = datetime.strftime(self.CurrentEventYear.end_time, "%d %B %Y")
arr_date = datetime.strftime(self.CurrentEventYear.start_time, "%d %B %Y")
dep_date = datetime.strftime(self.CurrentEventYear.end_time, "%d %B %Y")

for oneday in myDayRange:
for one_day in my_day_range:
if arrival:
TmpDay = self.CurrentEventYear.end_time - timedelta(days=oneday)
tmp_day = self.CurrentEventYear.end_time - timedelta(days=one_day)
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")
if arrival and ArrDate == DayString:
TabResult.append((DayNum, DayName, 'selected="selected"'))
elif departure and DepDate == DayString:
TabResult.append((DayNum, DayName, 'selected="selected"'))
tmp_day = self.CurrentEventYear.start_time + timedelta(days=one_day)
day_name = datetime.strftime(tmp_day, "%A")
day_num = datetime.strftime(tmp_day, "%d/%m/%y")
day_string = datetime.strftime(tmp_day, "%d %B %Y")
if arrival and arr_date == day_string:
tab_result.append((day_num, day_name, 'selected="selected"'))
elif departure and dep_date == day_string:
tab_result.append((day_num, day_name, 'selected="selected"'))
else:
TabResult.append((DayNum, DayName, ""))
return TabResult
tab_result.append((day_num, day_name, ""))
return tab_result

def PossibleTime(self, typedate="arrival"):
ArrTime, DepTime = "10:00", "19:00"
TabResult = list()
def PossibleTime(self, type_date="arrival"):
arr_time, dep_time = "10:00", "19:00"
tab_result = list()

if self.Sejour:
ArrTime = datetime.strftime(self.Sejour.arrival_time, "%H:%M")
DepTime = datetime.strftime(self.Sejour.depart_time, "%H:%M")
arr_time = datetime.strftime(self.Sejour.arrival_time, "%H:%M")
dep_time = datetime.strftime(self.Sejour.depart_time, "%H:%M")

for hour in range(24):
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"'))
str_time = "%.2d:%.2d" % (hour, minutes)
disp_time = "%dh%.2d" % (hour, minutes)
if type_date == "arrival" and str_time == arr_time:
tab_result.append((str_time, disp_time, 'selected="selected"'))
elif type_date == "departure" and str_time == dep_time:
tab_result.append((str_time, disp_time, 'selected="selected"'))
else:
TabResult.append((StrTime, DispTime, ""))
return TabResult
tab_result.append((str_time, disp_time, ""))
return tab_result

def IsCheck(self, InputControl):
ListControlA = ['Arrival', 'Departure']
ListControlB = ['PMR', 'Cov', 'Bras', 'Other']
if InputControl not in map(':'.join, itertools.product(ListControlA, ListControlB)):
list_control_a = ['Arrival', 'Departure']
list_control_b = ['PMR', 'Cov', 'Bras', 'Other']
if InputControl not in map(':'.join, itertools.product(list_control_a, list_control_b)):
return ""
if self.Sejour:
if InputControl.startswith('Arrival'):
CtrlVal = 2 ** ListControlB.index(InputControl[8:])
if self.Sejour.arrival_check & CtrlVal == CtrlVal:
ctrl_val = 2 ** list_control_b.index(InputControl[8:])
if self.Sejour.arrival_check & ctrl_val == ctrl_val:
return "checked=\"checked\""
else:
return ""
elif InputControl.startswith('Departure'):
CtrlVal = 2 ** ListControlB.index(InputControl[10:])
if self.Sejour.depart_check & CtrlVal == CtrlVal:
ctrl_val = 2 ** list_control_b.index(InputControl[10:])
if self.Sejour.depart_check & ctrl_val == ctrl_val:
return "checked=\"checked\""
else:
return ""
@@ -146,9 +151,9 @@ class Orga_helpers(DummySejour):

def ChoosedList(self):
""" Return choice validated by user """
ListOrga = []
list_orga = []
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
list_orga.append(self.Orga_tasks[num])
return list_orga

+ 97
- 100
jm2l/to_print.py View File

@@ -1,9 +1,6 @@
# -*- coding: utf8 -*-
import io
from pyramid.response import Response
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
@@ -14,174 +11,174 @@ from .upload import MediaPath
from jm2l.const import CurrentYear

# Create PDF container
EXPIRATION_TIME = 300 # seconds
EXPIRATION_TIME = 300 # seconds
WIDTH = 210 * mm
HEIGHT = 297 * mm
ICONSIZE = 10 * mm


def JM2L_large_Logo(canvas, Offset=(0,0)):
def JM2L_large_Logo(canvas, Offset=(0, 0)):
OffX, OffY = Offset
canvas.setFont('Logo', 110)
canvas.setFillColorRGB(.83,0,.33)
canvas.drawCentredString(WIDTH/2-OffY, HEIGHT-100-OffX, "JM2L")
canvas.setFillColorRGB(.83, 0, .33)
canvas.drawCentredString(WIDTH / 2 - OffY, HEIGHT - 100 - OffX, "JM2L")

canvas.setFont("Helvetica-Bold", 30)
yearobject = canvas.beginText()
yearobject.setFillColorRGB(1,1,1)
yearobject.setTextRenderMode(0)
yearobject.setTextOrigin(WIDTH/2-OffY-120, HEIGHT-36-OffX)
yearobject.setWordSpace(48)
yearobject.textLines("2 0 1 5")
yearobject.setWordSpace(1)
canvas.drawText(yearobject)
year_object = canvas.beginText()
year_object.setFillColorRGB(1, 1, 1)
year_object.setTextRenderMode(0)
year_object.setTextOrigin(WIDTH / 2 - OffY - 120, HEIGHT - 36 - OffX)
year_object.setWordSpace(48)
year_object.textLines("2 0 1 5")
year_object.setWordSpace(1)
canvas.drawText(year_object)


def one_time_step(canvas, str, hour, max_size, offset):
max_x, max_y = max_size
off_x, off_y = offset
step_y = max_y/9
half_step = step_y/2
canvas.drawCentredString(off_x-30, max_y-step_y*hour+off_y-3, str)
hour_place = step_y*hour+off_y
canvas.line(off_x-5, hour_place, off_x, hour_place)
if hour<9:
canvas.line(off_x-2, hour_place+half_step, off_x, hour_place+half_step)
step_y = max_y / 9
half_step = step_y / 2
canvas.drawCentredString(off_x - 30, max_y - step_y * hour + off_y - 3, str)
hour_place = step_y * hour + off_y
canvas.line(off_x - 5, hour_place, off_x, hour_place)
if hour < 9:
canvas.line(off_x - 2, hour_place + half_step, off_x, hour_place + half_step)


@view_config(route_name='stand_print', http_cache = (EXPIRATION_TIME, {'public':True}))
@view_config(route_name='stand_print', http_cache=(EXPIRATION_TIME, {'public': True}))
def stand_print(request):
# Ok let's generate a print for place schedule
# Register LiberationMono font
ttfFile = "jm2l/static/fonts/LiberationMono-Regular.ttf"
pdfmetrics.registerFont(TTFont("Liberation", ttfFile))
# Import font
ttfFile_Logo = "jm2l/static/fonts/PWTinselLetters.ttf"
pdfmetrics.registerFont(TTFont("Logo", ttfFile_Logo))
pdf = StringIO.StringIO()
c = canvas.Canvas( pdf, pagesize=(HEIGHT, WIDTH) )
ttf_file = "jm2l/static/fonts/LiberationMono-Regular.ttf"
pdfmetrics.registerFont(TTFont("Liberation", ttf_file))
#  Import font
ttf_file_logo = "jm2l/static/fonts/PWTinselLetters.ttf"
pdfmetrics.registerFont(TTFont("Logo", ttf_file_logo))
pdf = io.BytesIO()
c = canvas.Canvas(pdf, pagesize=(HEIGHT, WIDTH))
c.translate(mm, mm)
# Feed some metadata
c.setCreator("linux-azur.org")
c.setTitle("Affiches stand")

c.saveState()
year = int(request.matchdict.get('year', CurrentYear))

Events = DBSession.query(Event)\
.filter(Event.for_year == year)\
Events = DBSession.query(Event) \
.filter(Event.for_year == year) \
.filter(Event.event_type == "Stand")

for ev in Events:
c.setFont('Logo', 50)
c.setFillColorRGB(.5,.5,.5)
c.drawString(HEIGHT-150, 30, "JM2L")
c.setFillColorRGB(.5, .5, .5)
c.drawString(HEIGHT - 150, 30, "JM2L")
c.setFont('Logo', 100)
c.setFillColorRGB(0.5,0.5,0.5)
c.drawCentredString(HEIGHT/2, WIDTH-90, "STAND", 0)
c.setFillColorRGB(0,0,0)
c.setFillColorRGB(0.5, 0.5, 0.5)
c.drawCentredString(HEIGHT / 2, WIDTH - 90, "STAND", 0)
c.setFillColorRGB(0, 0, 0)
c.setFont('Helvetica', 42)
c.drawCentredString(HEIGHT/2, WIDTH/2, ev.name, 0)
c.drawCentredString(HEIGHT / 2, WIDTH / 2, ev.name, 0)
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')


@view_config(route_name='place_print', http_cache = (EXPIRATION_TIME, {'public':True}))
@view_config(route_name='place_print', http_cache=(EXPIRATION_TIME, {'public': True}))
def place_print(request):
# Ok let's generate a print for place schedule
# Register LiberationMono font
ttfFile = "jm2l/static/fonts/LiberationMono-Regular.ttf"
pdfmetrics.registerFont(TTFont("Liberation", ttfFile))
# Import font
ttfFile_Logo = "jm2l/static/fonts/PWTinselLetters.ttf"
pdfmetrics.registerFont(TTFont("Logo", ttfFile_Logo))
pdf = StringIO.StringIO()
c = canvas.Canvas( pdf, pagesize=(WIDTH, HEIGHT) )
ttf_file = "jm2l/static/fonts/LiberationMono-Regular.ttf"
pdfmetrics.registerFont(TTFont("Liberation", ttf_file))
#  Import font
ttf_file_logo = "jm2l/static/fonts/PWTinselLetters.ttf"
pdfmetrics.registerFont(TTFont("Logo", ttf_file_logo))
pdf = io.BytesIO()
c = canvas.Canvas(pdf, pagesize=(WIDTH, HEIGHT))
c.translate(mm, mm)
# Feed some metadata
c.setCreator("linux-azur.org")
c.setTitle("Planning Salle")

c.saveState()
year = int(request.matchdict.get('year', CurrentYear))
# Initialization
# Compute days used by all events matching the specified input year
place_used = DBSession.query(Event.salle_uid)\
.filter(Event.for_year == year)\
.filter(Event.event_type != 'Stand')\
.group_by(Event.salle_uid)
place_used = DBSession.query(Event.salle_uid) \
.filter(Event.for_year == year) \
.filter(Event.event_type != 'Stand') \
.group_by(Event.salle_uid)
for place in place_used:
place_uid = place[0]
place_uid = place[0]
place_obj = Salles.by_id(place_uid)
# Logo on Top
JM2L_large_Logo(c)
max_size = (WIDTH-110, HEIGHT-300)
max_size = (WIDTH - 110, HEIGHT - 300)
offset = (70, 90)
c.setFillColorRGB(.5,.5,.5)
c.setFillColorRGB(.5, .5, .5)
c.setFont('Liberation', 40)
c.drawCentredString(WIDTH/2, HEIGHT-190, place_obj.name, 1)
c.drawCentredString(WIDTH / 2, HEIGHT - 190, place_obj.name, 1)
c.setFont('Liberation', 35)
c.drawCentredString(WIDTH/2, HEIGHT-145, place_obj.place_type, 0 )
c.setFont('Helvetica', 20)
c.drawCentredString(WIDTH/2, 55, place_obj.phy.name, 0)
c.drawCentredString(WIDTH / 2, HEIGHT - 145, place_obj.place_type, 0)
c.setFont('Helvetica', 20)
c.drawCentredString(WIDTH / 2, 55, place_obj.phy.name, 0)
# Timetable container
c.setLineWidth(.1)
c.setLineCap(2)
#c.setFillColorRGB(0,0,1)
# c.setFillColorRGB(0,0,1)
c.rect(offset[0], offset[1], max_size[0], max_size[1], fill=0, stroke=1)
c.setLineWidth(.5)
c.setLineWidth(.5)
# create time mark
c.setFillColorRGB(0,0,0)
c.setFillColorRGB(0, 0, 0)
c.setFont('Helvetica', 10)
for i in range(0,10):
one_time_step(c, "%.2dh00" % (i+10), i, max_size, offset)
#c.setFont('Helvetica', 12)
Events = DBSession.query(Event)\
.filter(Event.for_year == year)\
.filter(Event.salle_uid == place_uid)\
.order_by(Event.start_time)
for i in range(0, 10):
one_time_step(c, "%.2dh00" % (i + 10), i, max_size, offset)
# c.setFont('Helvetica', 12)
Events = DBSession.query(Event) \
.filter(Event.for_year == year) \
.filter(Event.salle_uid == place_uid) \
.order_by(Event.start_time)
for ev in Events:
place_time(c, ev, max_size, offset)
#c.rect(70, 50, WIDTH-100, HEIGHT-250, fill=0, stroke=1)
# c.rect(70, 50, WIDTH-100, HEIGHT-250, fill=0, stroke=1)
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')


def place_time(c, ev, max_size, offset):
max_x, max_y = max_size
off_x, off_y = offset
minute = max_y/(9*60)
start_pos_y = ((int( ev.start_time.strftime('%H') )-10)*60 + int( ev.start_time.strftime('%M') )) * minute
stop_pos_y = ((int( ev.end_time.strftime('%H') )-10)*60 + int( ev.end_time.strftime('%M') )) * minute

c.setFillColorRGB(0.98,0.98,0.98)
c.rect(offset[0], max_y + off_y - start_pos_y, max_size[0], start_pos_y-stop_pos_y, fill=1, stroke=1)
c.setFillColorRGB(0,0,0)
#c.drawString(off_x+5, max_y + off_y - 15 - start_pos_y, ev.start_time.strftime('%H:%M'), 0)
c.setFont('Helvetica', 12)
c.drawCentredString(WIDTH/2, max_y + off_y - 35 - start_pos_y, ev.name, 0)
intervs = ', '.join( [x.slug for x in ev.intervenants] )
c.setFont('Helvetica', 10)
c.drawCentredString(WIDTH/2, max_y + off_y - 55 - start_pos_y, intervs, 0)
minute = max_y / (9 * 60)
start_pos_y = ((int(ev.start_time.strftime('%H')) - 10) * 60 + int(ev.start_time.strftime('%M'))) * minute
stop_pos_y = ((int(ev.end_time.strftime('%H')) - 10) * 60 + int(ev.end_time.strftime('%M'))) * minute

c.setFillColorRGB(0.98, 0.98, 0.98)
c.rect(offset[0], max_y + off_y - start_pos_y, max_size[0], start_pos_y - stop_pos_y, fill=1, stroke=1)
c.setFillColorRGB(0, 0, 0)
# c.drawString(off_x+5, max_y + off_y - 15 - start_pos_y, ev.start_time.strftime('%H:%M'), 0)
c.setFont('Helvetica', 12)
c.drawCentredString(WIDTH / 2, max_y + off_y - 35 - start_pos_y, ev.name, 0)
intervs = ', '.join([x.slug for x in ev.intervenants])
c.setFont('Helvetica', 10)
c.drawCentredString(WIDTH / 2, max_y + off_y - 55 - start_pos_y, intervs, 0)

+ 4
- 2
jm2l/views.py View File

@@ -29,6 +29,7 @@ try:
from StringIO import StringIO
except ImportError:
from io import StringIO
import io
import paginate
import unicodedata
import datetime
@@ -1002,7 +1003,7 @@ def list_users_csv(request):
.outerjoin(adalias) \
.order_by(User.slug) \
.all()
FileHandle = StringIO.StringIO()
FileHandle = io.BytesIO()
fileWriter = csv.writer(FileHandle, delimiter=',', quotechar='"', quoting=csv.QUOTE_NONNUMERIC)
fileWriter.writerow(["Identifiant_JM2L", "Nom", "Prenom", "Status_%s" % for_year])
for user, sejour in Data:
@@ -1358,7 +1359,8 @@ def participer(request):
NewUser = TmpUsr

# Send the Welcome Mail
mailer = request.registry['mailer']
# mailer = request.registry['mailer']
mailer = request.mailer
# Prepare Plain Text Message :
Mail_template = Template(filename='jm2l/templates/mail_plain.mako')
mail_plain = Mail_template.render(request=request, User=NewUser, action="Welcome")


+ 5
- 2
setup.py View File

@@ -11,6 +11,7 @@ with open(os.path.join(here, 'CHANGES.txt')) as f:
## Do not forget to run for lxml dependencies
## apt-get install libxml2-dev libxslt1-dev


requires = [
'pyramid',
'pyramid_chameleon',
@@ -36,9 +37,11 @@ requires = [
'passlib',
'argon2_cffi',
'paginate',
'markupsafe'
'markupsafe',
'webhelpers2',
'email_validator',
'pyramid-scheduler'
]

setup(name='JM2L',
version='0.1',
description='JM2L',


Loading…
Cancel
Save