| @@ -38,7 +38,7 @@ If no error occurs, the webserver should be available on http://localhost:8080/ | |||||
| Enjoy ! | Enjoy ! | ||||
| sudo apt install virtualenv git python3-virtualenv | |||||
| sudo apt install virtualenv git python3-virtualenv imagemagick | |||||
| sudo mkdir -p /srv/jm2l | sudo mkdir -p /srv/jm2l | ||||
| cd /srv/jm2l/ | cd /srv/jm2l/ | ||||
| @@ -15,7 +15,6 @@ pyramid.debug_notfound = false | |||||
| pyramid.debug_routematch = false | pyramid.debug_routematch = false | ||||
| pyramid.default_locale_name = en | pyramid.default_locale_name = en | ||||
| pyramid.includes = | pyramid.includes = | ||||
| pyramid_mailer.testing | |||||
| pyramid_debugtoolbar | pyramid_debugtoolbar | ||||
| pyramid_tm | pyramid_tm | ||||
| pyramid_mako | pyramid_mako | ||||
| @@ -30,31 +30,31 @@ def add_renderer_globals(event): | |||||
| event['CurrentYear'] = CurrentYear | 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): | def mailer_tasks(config): | ||||
| # Send the Welcome Mail | # Send the Welcome Mail | ||||
| mailer = config.registry['mailer'] | 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 = Request.blank('/', base_url='http://jm2l.linux-azur.org') | ||||
| request.registry = config.registry | 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 | # Skip mail to contact | ||||
| if StaffUser == Contact: | |||||
| if staff_user == contact: | |||||
| continue | continue | ||||
| # Skip those that have no task assigned | # 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 | continue | ||||
| # Prepare Plain Text Message : | # 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 : | # 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 | # Prepare Message | ||||
| message = Message(subject="[JM2L] Le mail de rappel pour les JM2L !", | message = Message(subject="[JM2L] Le mail de rappel pour les JM2L !", | ||||
| sender="contact@jm2l.linux-azur.org", | sender="contact@jm2l.linux-azur.org", | ||||
| recipients=[StaffUser.mail], | |||||
| recipients=[staff_user.mail], | |||||
| body=mail_plain, html=mail_html) | body=mail_plain, html=mail_html) | ||||
| message.add_bcc("spam@style-python.fr") | message.add_bcc("spam@style-python.fr") | ||||
| @@ -81,8 +81,11 @@ def main(global_config, **settings): | |||||
| authentication_policy=authentication_policy, | authentication_policy=authentication_policy, | ||||
| authorization_policy=authorization_policy | authorization_policy=authorization_policy | ||||
| ) | ) | ||||
| #config.include('pyramid_mailer') | |||||
| config.include('pyramid_mailer.debug') | |||||
| config.add_subscriber(add_renderer_globals, BeforeRender) | 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() | config.registry['event_date'] = JM2L_Year.get_latest_jm2l_startdate() | ||||
| sched = BackgroundScheduler() | sched = BackgroundScheduler() | ||||
| sched.add_job(mailer_tasks, 'cron', day_of_week='fri', hour=18, args=[config]) | 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('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') | 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('entities', '/entities') # {sep:/*}{Nature:\w+?}') | ||||
| config.add_route('add_entity', '/entity') | config.add_route('add_entity', '/entity') | ||||
| config.add_route('delete_entity', r'/entity/{entity_id:(\d+)}/delete') | 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', r'/entity/{tiers_type:(\w+)}/{entity_id:([\w-]+)}/edit') | ||||
| config.add_route('edit_entity_cat', '/categorie/entity') | config.add_route('edit_entity_cat', '/categorie/entity') | ||||
| ## Users | |||||
| # Users | |||||
| config.add_route('pict_user', '/user_picture') | config.add_route('pict_user', '/user_picture') | ||||
| config.add_route('show_user', r'/user/{user_slug:([\w-]+)?}') | config.add_route('show_user', r'/user/{user_slug:([\w-]+)?}') | ||||
| config.add_route('badge_user', r'/user/{user_slug:([\w-]+)?}/badge') | config.add_route('badge_user', r'/user/{user_slug:([\w-]+)?}/badge') | ||||
| @@ -6,6 +6,7 @@ try: | |||||
| from StringIO import StringIO | from StringIO import StringIO | ||||
| except ImportError: | except ImportError: | ||||
| from io import StringIO | from io import StringIO | ||||
| import io | |||||
| from pyramid.view import view_config | from pyramid.view import view_config | ||||
| from .models import DBSession, User | from .models import DBSession, User | ||||
| from reportlab.pdfgen import canvas | from reportlab.pdfgen import canvas | ||||
| @@ -25,38 +26,38 @@ 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.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 | num = 0 | ||||
| canvas.setStrokeColorRGB(0.5, 0.5, 0.5) | canvas.setStrokeColorRGB(0.5, 0.5, 0.5) | ||||
| Logos = list() | |||||
| list_logos = list() | |||||
| for thumb in DispUser.tiers: | for thumb in DispUser.tiers: | ||||
| if thumb.ThumbLinks: | 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 ? | # Should We compute a better positionning for logos ? | ||||
| DicPos = {} | DicPos = {} | ||||
| DicPos[1] = {0: (1. / 2, 1. / 2)} | 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), | 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)} | 6: (5. / 8, 3. / 4), 7: (7. / 8, 3. / 4)} | ||||
| # draw overall border | # 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) | canvas.setLineWidth(.1) | ||||
| if len(Logos) > 1: | |||||
| if len(list_logos) > 1: | |||||
| size = ICONSIZE | size = ICONSIZE | ||||
| else: | else: | ||||
| size = ICONSIZE * 1.5 | size = ICONSIZE * 1.5 | ||||
| canvas.drawImage(ImagePath, | |||||
| PosX, PosY, size, size, | |||||
| canvas.drawImage(image_path, | |||||
| pos_x, pos_y, size, size, | |||||
| preserveAspectRatio=True, | preserveAspectRatio=True, | ||||
| anchor='c', | anchor='c', | ||||
| mask='auto' | mask='auto' | ||||
| ) | ) | ||||
| # draw icon border | # 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 | num += 1 | ||||
| @@ -114,37 +115,37 @@ def QRCode(DispUser): | |||||
| def one_badge(c, DispUser, Offset=(0, 0)): | def one_badge(c, DispUser, Offset=(0, 0)): | ||||
| # Logo on Top | # Logo on Top | ||||
| JM2L_Logo(c, Offset) | 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: | if DispUser.Staff: | ||||
| # Staff | # Staff | ||||
| c.setFillColorRGB(.83, 0, .33) | 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.setFillColorRGB(1, 1, 1) | ||||
| c.setFont('Liberation', 30) | 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: | elif DispUser.is_Intervenant: | ||||
| # Intervenant | # Intervenant | ||||
| c.setFillColorRGB(.21, .67, .78) | 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.setFillColorRGB(1, 1, 1) | ||||
| c.setFont('Liberation', 30) | 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: | elif DispUser.is_crew: | ||||
| # Benevole | # Benevole | ||||
| c.setFillColorRGB(.18, .76, .23) | 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.setFillColorRGB(1, 1, 1) | ||||
| c.setFont('Liberation', 30) | 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: | else: | ||||
| # Visiteur | # Visiteur | ||||
| c.setFillColorRGB(.8, .8, .8) | 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.setFillColorRGB(1, 1, 1) | ||||
| c.setFont('Liberation', 30) | 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() | c.restoreState() | ||||
| @@ -154,25 +155,25 @@ def one_badge(c, DispUser, Offset=(0, 0)): | |||||
| # Feed Name and SurName | # 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: | 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.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: | 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.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: | 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: | if DispUser.pseudo: | ||||
| c.setFont("Helvetica-Oblique", 18) | 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 | # 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') | anchor='s') | ||||
| Tiers_Logo(c, DispUser, None, Offset) | Tiers_Logo(c, DispUser, None, Offset) | ||||
| @@ -192,14 +193,14 @@ def badge_user(request): | |||||
| # Ok let's generate a PDF Badge | # Ok let's generate a PDF Badge | ||||
| # Register LiberationMono font | # 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 | # 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 = canvas.Canvas(pdf, pagesize=(WIDTH, HEIGHT)) | ||||
| c.translate(mm, mm) | c.translate(mm, mm) | ||||
| @@ -211,23 +212,21 @@ def badge_user(request): | |||||
| c.saveState() | c.saveState() | ||||
| one_badge(c, DispUser) | 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.showPage() | ||||
| c._filename = OutPDF | |||||
| c.save() | c.save() | ||||
| pdf.seek(0) | pdf.seek(0) | ||||
| if isoutpng: | 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 | # 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) | 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) | out_img.seek(0) | ||||
| return Response(app_iter=out_img, content_type='image/png') | return Response(app_iter=out_img, content_type='image/png') | ||||
| @@ -246,13 +245,13 @@ def planche_badge(request): | |||||
| # .filter(User_Event.year_uid == year) | # .filter(User_Event.year_uid == year) | ||||
| # Register LiberationMono font | # 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 | # 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 | FULLWIDTH = 210 * mm | ||||
| FULLHEIGHT = 297 * mm | FULLHEIGHT = 297 * mm | ||||
| @@ -264,11 +263,11 @@ def planche_badge(request): | |||||
| c.setCreator("linux-azur.org") | c.setCreator("linux-azur.org") | ||||
| c.setTitle("Badge") | 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): | |||||
| 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() | 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: | if num % 8 == 7: | ||||
| t = num + 1 | t = num + 1 | ||||
| c.showPage() | c.showPage() | ||||
| @@ -115,8 +115,8 @@ class _PyCaptcha_SineWarp(_PyCaptcha_WarpBase): | |||||
| @view_config(route_name='captcha') | @view_config(route_name='captcha') | ||||
| def DoCaptcha(request): | 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 | Xmax, Ymax = work_img.size | ||||
| # Write something on it | # Write something on it | ||||
| draw = ImageDraw.Draw(work_img) | draw = ImageDraw.Draw(work_img) | ||||
| @@ -129,7 +129,7 @@ def DoCaptcha(request): | |||||
| # Choose a word for captcha | # Choose a word for captcha | ||||
| text = random.choice(TabMots) | text = random.choice(TabMots) | ||||
| Xt, Yt = font.getsize(text) | 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") | draw.text((OrX, OrY), text, font=font, fill="#000000") | ||||
| # Apply a Blur | # Apply a Blur | ||||
| # work_img=work_img.filter(ImageFilter.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)) | 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)) | bx, by = (random.uniform(0.5, 0.8), random.uniform(0, 0.2)) | ||||
| # Apply perspective to Captcha | # 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 | # Apply SinWarp to Captcha | ||||
| tr = Captcha_Img(Xmax, Ymax) | tr = Captcha_Img(Xmax, Ymax) | ||||
| tr._image = work_img | tr._image = work_img | ||||
| @@ -11,17 +11,20 @@ from wtforms.csrf.session import SessionCSRF | |||||
| from datetime import timedelta | from datetime import timedelta | ||||
| from jm2l.const import CurrentYear | from jm2l.const import CurrentYear | ||||
| # What about an helper function | # 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 | # get random string password with letters, digits, and symbols | ||||
| def get_random_string(length): | def get_random_string(length): | ||||
| csrf_characters = string.ascii_letters + string.digits + string.punctuation | 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): | class MyBaseForm(Form): | ||||
| @@ -155,32 +158,38 @@ class ConfCreateForm(MyBaseForm): | |||||
| start_time = HiddenField() | start_time = HiddenField() | ||||
| end_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): | class ConfUpdateForm(ConfCreateForm): | ||||
| @@ -223,9 +232,10 @@ class PlaceCreateForm(MyBaseForm): | |||||
| filters=[strip_filter]) | filters=[strip_filter]) | ||||
| name = StringField('Nom Complet', [validators.Length(min=1, max=80)], | name = StringField('Nom Complet', [validators.Length(min=1, max=80)], | ||||
| filters=[strip_filter]) | 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]) | filters=[strip_filter]) | ||||
| adresse = TextAreaField('Adresse', [validators.Length(max=100)], | adresse = TextAreaField('Adresse', [validators.Length(max=100)], | ||||
| filters=[strip_filter]) | filters=[strip_filter]) | ||||
| @@ -600,13 +610,16 @@ class PropMForm(MyBaseForm): | |||||
| message=u"doit être sous la forme HH:MM")], | message=u"doit être sous la forme HH:MM")], | ||||
| filters=[strip_filter]) | filters=[strip_filter]) | ||||
| end_time = HiddenField() | 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): | class UpdateAskCForm(AskCForm, UpdateExchangeForm): | ||||
| @@ -5,6 +5,11 @@ import itertools | |||||
| from jm2l.const import CurrentYear | 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): | class DummySejour(object): | ||||
| def __init__(self, event): | def __init__(self, event): | ||||
| @@ -29,78 +34,78 @@ class Sejour_helpers(DummySejour): | |||||
| # This function return the start of the event | # This function return the start of the event | ||||
| return self.CurrentYear | return self.CurrentYear | ||||
| def PossibleDate(self, typedate="arrival"): | |||||
| def PossibleDate(self, type_date="arrival"): | |||||
| arrival, departure = False, False | 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 | # Let's say people should arrive until 2 day before | ||||
| arrival = True | 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 | # Let's say people should go back home until 2 day after | ||||
| departure = True | departure = True | ||||
| myDayRange = range(3) | |||||
| my_day_range = range(3) | |||||
| else: | else: | ||||
| return TabResult | |||||
| return tab_result | |||||
| if self.Sejour: | 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: | 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: | if arrival: | ||||
| TmpDay = self.CurrentEventYear.end_time - timedelta(days=oneday) | |||||
| tmp_day = self.CurrentEventYear.end_time - timedelta(days=one_day) | |||||
| elif departure: | 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: | 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: | 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 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"')) | |||||
| 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: | else: | ||||
| TabResult.append((StrTime, DispTime, "")) | |||||
| return TabResult | |||||
| tab_result.append((str_time, disp_time, "")) | |||||
| return tab_result | |||||
| def IsCheck(self, InputControl): | 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 "" | return "" | ||||
| if self.Sejour: | if self.Sejour: | ||||
| if InputControl.startswith('Arrival'): | 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\"" | return "checked=\"checked\"" | ||||
| else: | else: | ||||
| return "" | return "" | ||||
| elif InputControl.startswith('Departure'): | 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\"" | return "checked=\"checked\"" | ||||
| else: | else: | ||||
| return "" | return "" | ||||
| @@ -146,9 +151,9 @@ class Orga_helpers(DummySejour): | |||||
| def ChoosedList(self): | def ChoosedList(self): | ||||
| """ Return choice validated by user """ | """ Return choice validated by user """ | ||||
| ListOrga = [] | |||||
| list_orga = [] | |||||
| for num in range(0, len(self.Orga_tasks)): | for num in range(0, len(self.Orga_tasks)): | ||||
| curs = 2 ** num | curs = 2 ** num | ||||
| if self.Sejour.orga_part & curs == curs: | 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 | |||||
| @@ -1,9 +1,6 @@ | |||||
| # -*- coding: utf8 -*- | # -*- coding: utf8 -*- | ||||
| import io | |||||
| from pyramid.response import Response | from pyramid.response import Response | ||||
| try: | |||||
| from StringIO import StringIO | |||||
| except ImportError: | |||||
| from io import StringIO | |||||
| from pyramid.view import view_config | from pyramid.view import view_config | ||||
| from .models import DBSession, Event, Salles | from .models import DBSession, Event, Salles | ||||
| from reportlab.pdfgen import canvas | from reportlab.pdfgen import canvas | ||||
| @@ -14,174 +11,174 @@ from .upload import MediaPath | |||||
| from jm2l.const import CurrentYear | from jm2l.const import CurrentYear | ||||
| # Create PDF container | # Create PDF container | ||||
| EXPIRATION_TIME = 300 # seconds | |||||
| EXPIRATION_TIME = 300 # seconds | |||||
| WIDTH = 210 * mm | WIDTH = 210 * mm | ||||
| HEIGHT = 297 * mm | HEIGHT = 297 * mm | ||||
| ICONSIZE = 10 * mm | ICONSIZE = 10 * mm | ||||
| def JM2L_large_Logo(canvas, Offset=(0,0)): | |||||
| def JM2L_large_Logo(canvas, Offset=(0, 0)): | |||||
| OffX, OffY = Offset | OffX, OffY = Offset | ||||
| canvas.setFont('Logo', 110) | 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) | 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): | def one_time_step(canvas, str, hour, max_size, offset): | ||||
| max_x, max_y = max_size | max_x, max_y = max_size | ||||
| off_x, off_y = offset | 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): | def stand_print(request): | ||||
| # Ok let's generate a print for place schedule | # Ok let's generate a print for place schedule | ||||
| # Register LiberationMono font | # 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) | c.translate(mm, mm) | ||||
| # Feed some metadata | # Feed some metadata | ||||
| c.setCreator("linux-azur.org") | c.setCreator("linux-azur.org") | ||||
| c.setTitle("Affiches stand") | c.setTitle("Affiches stand") | ||||
| c.saveState() | c.saveState() | ||||
| year = int(request.matchdict.get('year', CurrentYear)) | 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") | .filter(Event.event_type == "Stand") | ||||
| for ev in Events: | for ev in Events: | ||||
| c.setFont('Logo', 50) | 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.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.setFont('Helvetica', 42) | ||||
| c.drawCentredString(HEIGHT/2, WIDTH/2, ev.name, 0) | |||||
| c.drawCentredString(HEIGHT / 2, WIDTH / 2, ev.name, 0) | |||||
| c.showPage() | c.showPage() | ||||
| c.save() | c.save() | ||||
| pdf.seek(0) | 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): | def place_print(request): | ||||
| # Ok let's generate a print for place schedule | # Ok let's generate a print for place schedule | ||||
| # Register LiberationMono font | # 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) | c.translate(mm, mm) | ||||
| # Feed some metadata | # Feed some metadata | ||||
| c.setCreator("linux-azur.org") | c.setCreator("linux-azur.org") | ||||
| c.setTitle("Planning Salle") | c.setTitle("Planning Salle") | ||||
| c.saveState() | c.saveState() | ||||
| year = int(request.matchdict.get('year', CurrentYear)) | year = int(request.matchdict.get('year', CurrentYear)) | ||||
| # Initialization | # Initialization | ||||
| # Compute days used by all events matching the specified input year | # 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: | for place in place_used: | ||||
| place_uid = place[0] | |||||
| place_uid = place[0] | |||||
| place_obj = Salles.by_id(place_uid) | place_obj = Salles.by_id(place_uid) | ||||
| # Logo on Top | # Logo on Top | ||||
| JM2L_large_Logo(c) | JM2L_large_Logo(c) | ||||
| max_size = (WIDTH-110, HEIGHT-300) | |||||
| max_size = (WIDTH - 110, HEIGHT - 300) | |||||
| offset = (70, 90) | offset = (70, 90) | ||||
| c.setFillColorRGB(.5,.5,.5) | |||||
| c.setFillColorRGB(.5, .5, .5) | |||||
| c.setFont('Liberation', 40) | 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.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 | # Timetable container | ||||
| c.setLineWidth(.1) | c.setLineWidth(.1) | ||||
| c.setLineCap(2) | 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.rect(offset[0], offset[1], max_size[0], max_size[1], fill=0, stroke=1) | ||||
| c.setLineWidth(.5) | |||||
| c.setLineWidth(.5) | |||||
| # create time mark | # create time mark | ||||
| c.setFillColorRGB(0,0,0) | |||||
| c.setFillColorRGB(0, 0, 0) | |||||
| c.setFont('Helvetica', 10) | 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: | for ev in Events: | ||||
| place_time(c, ev, max_size, offset) | 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.showPage() | ||||
| c.save() | c.save() | ||||
| pdf.seek(0) | 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): | def place_time(c, ev, max_size, offset): | ||||
| max_x, max_y = max_size | max_x, max_y = max_size | ||||
| off_x, off_y = offset | 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) | |||||
| @@ -29,6 +29,7 @@ try: | |||||
| from StringIO import StringIO | from StringIO import StringIO | ||||
| except ImportError: | except ImportError: | ||||
| from io import StringIO | from io import StringIO | ||||
| import io | |||||
| import paginate | import paginate | ||||
| import unicodedata | import unicodedata | ||||
| import datetime | import datetime | ||||
| @@ -1002,7 +1003,7 @@ def list_users_csv(request): | |||||
| .outerjoin(adalias) \ | .outerjoin(adalias) \ | ||||
| .order_by(User.slug) \ | .order_by(User.slug) \ | ||||
| .all() | .all() | ||||
| FileHandle = StringIO.StringIO() | |||||
| FileHandle = io.BytesIO() | |||||
| fileWriter = csv.writer(FileHandle, delimiter=',', quotechar='"', quoting=csv.QUOTE_NONNUMERIC) | fileWriter = csv.writer(FileHandle, delimiter=',', quotechar='"', quoting=csv.QUOTE_NONNUMERIC) | ||||
| fileWriter.writerow(["Identifiant_JM2L", "Nom", "Prenom", "Status_%s" % for_year]) | fileWriter.writerow(["Identifiant_JM2L", "Nom", "Prenom", "Status_%s" % for_year]) | ||||
| for user, sejour in Data: | for user, sejour in Data: | ||||
| @@ -1358,7 +1359,8 @@ def participer(request): | |||||
| NewUser = TmpUsr | NewUser = TmpUsr | ||||
| # Send the Welcome Mail | # Send the Welcome Mail | ||||
| mailer = request.registry['mailer'] | |||||
| # mailer = request.registry['mailer'] | |||||
| mailer = request.mailer | |||||
| # Prepare Plain Text Message : | # Prepare Plain Text Message : | ||||
| Mail_template = Template(filename='jm2l/templates/mail_plain.mako') | Mail_template = Template(filename='jm2l/templates/mail_plain.mako') | ||||
| mail_plain = Mail_template.render(request=request, User=NewUser, action="Welcome") | mail_plain = Mail_template.render(request=request, User=NewUser, action="Welcome") | ||||
| @@ -11,6 +11,7 @@ with open(os.path.join(here, 'CHANGES.txt')) as f: | |||||
| ## Do not forget to run for lxml dependencies | ## Do not forget to run for lxml dependencies | ||||
| ## apt-get install libxml2-dev libxslt1-dev | ## apt-get install libxml2-dev libxslt1-dev | ||||
| requires = [ | requires = [ | ||||
| 'pyramid', | 'pyramid', | ||||
| 'pyramid_chameleon', | 'pyramid_chameleon', | ||||
| @@ -36,9 +37,11 @@ requires = [ | |||||
| 'passlib', | 'passlib', | ||||
| 'argon2_cffi', | 'argon2_cffi', | ||||
| 'paginate', | 'paginate', | ||||
| 'markupsafe' | |||||
| 'markupsafe', | |||||
| 'webhelpers2', | |||||
| 'email_validator', | |||||
| 'pyramid-scheduler' | |||||
| ] | ] | ||||
| setup(name='JM2L', | setup(name='JM2L', | ||||
| version='0.1', | version='0.1', | ||||
| description='JM2L', | description='JM2L', | ||||