From 2b3e8116d5b237bd8e2e0967324b52f7d39f1d6f Mon Sep 17 00:00:00 2001 From: tr4ck3ur Date: Sat, 8 Aug 2020 17:02:12 +0200 Subject: [PATCH] Fixing python3 issues --- README.txt | 2 +- development.ini | 1 - jm2l/__init__.py | 29 +++---- jm2l/badge.py | 163 +++++++++++++++++++-------------------- jm2l/captcha.py | 8 +- jm2l/forms.py | 95 +++++++++++++---------- jm2l/helpers.py | 97 ++++++++++++----------- jm2l/to_print.py | 197 +++++++++++++++++++++++------------------------ jm2l/views.py | 6 +- setup.py | 7 +- 10 files changed, 313 insertions(+), 292 deletions(-) diff --git a/README.txt b/README.txt index 6783a6c..3790517 100644 --- a/README.txt +++ b/README.txt @@ -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/ diff --git a/development.ini b/development.ini index 61308c2..c18a7b0 100644 --- a/development.ini +++ b/development.ini @@ -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 diff --git a/jm2l/__init__.py b/jm2l/__init__.py index e075426..3b5a18f 100644 --- a/jm2l/__init__.py +++ b/jm2l/__init__.py @@ -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') diff --git a/jm2l/badge.py b/jm2l/badge.py index b14b48e..97f8750 100644 --- a/jm2l/badge.py +++ b/jm2l/badge.py @@ -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() diff --git a/jm2l/captcha.py b/jm2l/captcha.py index 9d148ba..a33c8ba 100644 --- a/jm2l/captcha.py +++ b/jm2l/captcha.py @@ -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 diff --git a/jm2l/forms.py b/jm2l/forms.py index 161c21f..1dc3444 100644 --- a/jm2l/forms.py +++ b/jm2l/forms.py @@ -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): diff --git a/jm2l/helpers.py b/jm2l/helpers.py index c0fb852..c9aa525 100644 --- a/jm2l/helpers.py +++ b/jm2l/helpers.py @@ -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 diff --git a/jm2l/to_print.py b/jm2l/to_print.py index 2560e12..ff0170c 100644 --- a/jm2l/to_print.py +++ b/jm2l/to_print.py @@ -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) - \ No newline at end of file + 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) diff --git a/jm2l/views.py b/jm2l/views.py index 2426367..4446a95 100644 --- a/jm2l/views.py +++ b/jm2l/views.py @@ -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") diff --git a/setup.py b/setup.py index d28ae1c..ad798e4 100644 --- a/setup.py +++ b/setup.py @@ -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',