| @@ -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/ | |||
| @@ -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 | |||
| @@ -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') | |||
| @@ -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() | |||
| @@ -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 | |||
| @@ -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): | |||
| @@ -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 | |||
| @@ -1,9 +1,6 @@ | |||
| # -*- coding: utf8 -*- | |||
| import io | |||
| from pyramid.response import Response | |||
| try: | |||
| from StringIO import StringIO | |||
| except ImportError: | |||
| from io import StringIO | |||
| from pyramid.view import view_config | |||
| from .models import DBSession, Event, Salles | |||
| from reportlab.pdfgen import canvas | |||
| @@ -14,174 +11,174 @@ from .upload import MediaPath | |||
| from jm2l.const import CurrentYear | |||
| # Create PDF container | |||
| EXPIRATION_TIME = 300 # seconds | |||
| EXPIRATION_TIME = 300 # seconds | |||
| WIDTH = 210 * mm | |||
| HEIGHT = 297 * mm | |||
| ICONSIZE = 10 * mm | |||
| def JM2L_large_Logo(canvas, Offset=(0,0)): | |||
| def JM2L_large_Logo(canvas, Offset=(0, 0)): | |||
| OffX, OffY = Offset | |||
| canvas.setFont('Logo', 110) | |||
| canvas.setFillColorRGB(.83,0,.33) | |||
| canvas.drawCentredString(WIDTH/2-OffY, HEIGHT-100-OffX, "JM2L") | |||
| canvas.setFillColorRGB(.83, 0, .33) | |||
| canvas.drawCentredString(WIDTH / 2 - OffY, HEIGHT - 100 - OffX, "JM2L") | |||
| canvas.setFont("Helvetica-Bold", 30) | |||
| yearobject = canvas.beginText() | |||
| yearobject.setFillColorRGB(1,1,1) | |||
| yearobject.setTextRenderMode(0) | |||
| yearobject.setTextOrigin(WIDTH/2-OffY-120, HEIGHT-36-OffX) | |||
| yearobject.setWordSpace(48) | |||
| yearobject.textLines("2 0 1 5") | |||
| yearobject.setWordSpace(1) | |||
| canvas.drawText(yearobject) | |||
| year_object = canvas.beginText() | |||
| year_object.setFillColorRGB(1, 1, 1) | |||
| year_object.setTextRenderMode(0) | |||
| year_object.setTextOrigin(WIDTH / 2 - OffY - 120, HEIGHT - 36 - OffX) | |||
| year_object.setWordSpace(48) | |||
| year_object.textLines("2 0 1 5") | |||
| year_object.setWordSpace(1) | |||
| canvas.drawText(year_object) | |||
| def one_time_step(canvas, str, hour, max_size, offset): | |||
| max_x, max_y = max_size | |||
| off_x, off_y = offset | |||
| step_y = max_y/9 | |||
| half_step = step_y/2 | |||
| canvas.drawCentredString(off_x-30, max_y-step_y*hour+off_y-3, str) | |||
| hour_place = step_y*hour+off_y | |||
| canvas.line(off_x-5, hour_place, off_x, hour_place) | |||
| if hour<9: | |||
| canvas.line(off_x-2, hour_place+half_step, off_x, hour_place+half_step) | |||
| step_y = max_y / 9 | |||
| half_step = step_y / 2 | |||
| canvas.drawCentredString(off_x - 30, max_y - step_y * hour + off_y - 3, str) | |||
| hour_place = step_y * hour + off_y | |||
| canvas.line(off_x - 5, hour_place, off_x, hour_place) | |||
| if hour < 9: | |||
| canvas.line(off_x - 2, hour_place + half_step, off_x, hour_place + half_step) | |||
| @view_config(route_name='stand_print', http_cache = (EXPIRATION_TIME, {'public':True})) | |||
| @view_config(route_name='stand_print', http_cache=(EXPIRATION_TIME, {'public': True})) | |||
| def stand_print(request): | |||
| # Ok let's generate a print for place schedule | |||
| # Register LiberationMono font | |||
| ttfFile = "jm2l/static/fonts/LiberationMono-Regular.ttf" | |||
| pdfmetrics.registerFont(TTFont("Liberation", ttfFile)) | |||
| # Import font | |||
| ttfFile_Logo = "jm2l/static/fonts/PWTinselLetters.ttf" | |||
| pdfmetrics.registerFont(TTFont("Logo", ttfFile_Logo)) | |||
| pdf = StringIO.StringIO() | |||
| c = canvas.Canvas( pdf, pagesize=(HEIGHT, WIDTH) ) | |||
| ttf_file = "jm2l/static/fonts/LiberationMono-Regular.ttf" | |||
| pdfmetrics.registerFont(TTFont("Liberation", ttf_file)) | |||
| # Import font | |||
| ttf_file_logo = "jm2l/static/fonts/PWTinselLetters.ttf" | |||
| pdfmetrics.registerFont(TTFont("Logo", ttf_file_logo)) | |||
| pdf = io.BytesIO() | |||
| c = canvas.Canvas(pdf, pagesize=(HEIGHT, WIDTH)) | |||
| c.translate(mm, mm) | |||
| # Feed some metadata | |||
| c.setCreator("linux-azur.org") | |||
| c.setTitle("Affiches stand") | |||
| c.saveState() | |||
| year = int(request.matchdict.get('year', CurrentYear)) | |||
| Events = DBSession.query(Event)\ | |||
| .filter(Event.for_year == year)\ | |||
| Events = DBSession.query(Event) \ | |||
| .filter(Event.for_year == year) \ | |||
| .filter(Event.event_type == "Stand") | |||
| for ev in Events: | |||
| c.setFont('Logo', 50) | |||
| c.setFillColorRGB(.5,.5,.5) | |||
| c.drawString(HEIGHT-150, 30, "JM2L") | |||
| c.setFillColorRGB(.5, .5, .5) | |||
| c.drawString(HEIGHT - 150, 30, "JM2L") | |||
| c.setFont('Logo', 100) | |||
| c.setFillColorRGB(0.5,0.5,0.5) | |||
| c.drawCentredString(HEIGHT/2, WIDTH-90, "STAND", 0) | |||
| c.setFillColorRGB(0,0,0) | |||
| c.setFillColorRGB(0.5, 0.5, 0.5) | |||
| c.drawCentredString(HEIGHT / 2, WIDTH - 90, "STAND", 0) | |||
| c.setFillColorRGB(0, 0, 0) | |||
| c.setFont('Helvetica', 42) | |||
| c.drawCentredString(HEIGHT/2, WIDTH/2, ev.name, 0) | |||
| c.drawCentredString(HEIGHT / 2, WIDTH / 2, ev.name, 0) | |||
| c.showPage() | |||
| c.save() | |||
| pdf.seek(0) | |||
| return Response(app_iter=pdf, content_type = 'application/pdf' ) | |||
| return Response(app_iter=pdf, content_type='application/pdf') | |||
| @view_config(route_name='place_print', http_cache = (EXPIRATION_TIME, {'public':True})) | |||
| @view_config(route_name='place_print', http_cache=(EXPIRATION_TIME, {'public': True})) | |||
| def place_print(request): | |||
| # Ok let's generate a print for place schedule | |||
| # Register LiberationMono font | |||
| ttfFile = "jm2l/static/fonts/LiberationMono-Regular.ttf" | |||
| pdfmetrics.registerFont(TTFont("Liberation", ttfFile)) | |||
| # Import font | |||
| ttfFile_Logo = "jm2l/static/fonts/PWTinselLetters.ttf" | |||
| pdfmetrics.registerFont(TTFont("Logo", ttfFile_Logo)) | |||
| pdf = StringIO.StringIO() | |||
| c = canvas.Canvas( pdf, pagesize=(WIDTH, HEIGHT) ) | |||
| ttf_file = "jm2l/static/fonts/LiberationMono-Regular.ttf" | |||
| pdfmetrics.registerFont(TTFont("Liberation", ttf_file)) | |||
| # Import font | |||
| ttf_file_logo = "jm2l/static/fonts/PWTinselLetters.ttf" | |||
| pdfmetrics.registerFont(TTFont("Logo", ttf_file_logo)) | |||
| pdf = io.BytesIO() | |||
| c = canvas.Canvas(pdf, pagesize=(WIDTH, HEIGHT)) | |||
| c.translate(mm, mm) | |||
| # Feed some metadata | |||
| c.setCreator("linux-azur.org") | |||
| c.setTitle("Planning Salle") | |||
| c.saveState() | |||
| year = int(request.matchdict.get('year', CurrentYear)) | |||
| # Initialization | |||
| # Compute days used by all events matching the specified input year | |||
| place_used = DBSession.query(Event.salle_uid)\ | |||
| .filter(Event.for_year == year)\ | |||
| .filter(Event.event_type != 'Stand')\ | |||
| .group_by(Event.salle_uid) | |||
| place_used = DBSession.query(Event.salle_uid) \ | |||
| .filter(Event.for_year == year) \ | |||
| .filter(Event.event_type != 'Stand') \ | |||
| .group_by(Event.salle_uid) | |||
| for place in place_used: | |||
| place_uid = place[0] | |||
| place_uid = place[0] | |||
| place_obj = Salles.by_id(place_uid) | |||
| # Logo on Top | |||
| JM2L_large_Logo(c) | |||
| max_size = (WIDTH-110, HEIGHT-300) | |||
| max_size = (WIDTH - 110, HEIGHT - 300) | |||
| offset = (70, 90) | |||
| c.setFillColorRGB(.5,.5,.5) | |||
| c.setFillColorRGB(.5, .5, .5) | |||
| c.setFont('Liberation', 40) | |||
| c.drawCentredString(WIDTH/2, HEIGHT-190, place_obj.name, 1) | |||
| c.drawCentredString(WIDTH / 2, HEIGHT - 190, place_obj.name, 1) | |||
| c.setFont('Liberation', 35) | |||
| c.drawCentredString(WIDTH/2, HEIGHT-145, place_obj.place_type, 0 ) | |||
| c.setFont('Helvetica', 20) | |||
| c.drawCentredString(WIDTH/2, 55, place_obj.phy.name, 0) | |||
| c.drawCentredString(WIDTH / 2, HEIGHT - 145, place_obj.place_type, 0) | |||
| c.setFont('Helvetica', 20) | |||
| c.drawCentredString(WIDTH / 2, 55, place_obj.phy.name, 0) | |||
| # Timetable container | |||
| c.setLineWidth(.1) | |||
| c.setLineCap(2) | |||
| #c.setFillColorRGB(0,0,1) | |||
| # c.setFillColorRGB(0,0,1) | |||
| c.rect(offset[0], offset[1], max_size[0], max_size[1], fill=0, stroke=1) | |||
| c.setLineWidth(.5) | |||
| c.setLineWidth(.5) | |||
| # create time mark | |||
| c.setFillColorRGB(0,0,0) | |||
| c.setFillColorRGB(0, 0, 0) | |||
| c.setFont('Helvetica', 10) | |||
| for i in range(0,10): | |||
| one_time_step(c, "%.2dh00" % (i+10), i, max_size, offset) | |||
| #c.setFont('Helvetica', 12) | |||
| Events = DBSession.query(Event)\ | |||
| .filter(Event.for_year == year)\ | |||
| .filter(Event.salle_uid == place_uid)\ | |||
| .order_by(Event.start_time) | |||
| for i in range(0, 10): | |||
| one_time_step(c, "%.2dh00" % (i + 10), i, max_size, offset) | |||
| # c.setFont('Helvetica', 12) | |||
| Events = DBSession.query(Event) \ | |||
| .filter(Event.for_year == year) \ | |||
| .filter(Event.salle_uid == place_uid) \ | |||
| .order_by(Event.start_time) | |||
| for ev in Events: | |||
| place_time(c, ev, max_size, offset) | |||
| #c.rect(70, 50, WIDTH-100, HEIGHT-250, fill=0, stroke=1) | |||
| # c.rect(70, 50, WIDTH-100, HEIGHT-250, fill=0, stroke=1) | |||
| c.showPage() | |||
| c.save() | |||
| pdf.seek(0) | |||
| return Response(app_iter=pdf, content_type = 'application/pdf' ) | |||
| return Response(app_iter=pdf, content_type='application/pdf') | |||
| def place_time(c, ev, max_size, offset): | |||
| max_x, max_y = max_size | |||
| off_x, off_y = offset | |||
| minute = max_y/(9*60) | |||
| start_pos_y = ((int( ev.start_time.strftime('%H') )-10)*60 + int( ev.start_time.strftime('%M') )) * minute | |||
| stop_pos_y = ((int( ev.end_time.strftime('%H') )-10)*60 + int( ev.end_time.strftime('%M') )) * minute | |||
| c.setFillColorRGB(0.98,0.98,0.98) | |||
| c.rect(offset[0], max_y + off_y - start_pos_y, max_size[0], start_pos_y-stop_pos_y, fill=1, stroke=1) | |||
| c.setFillColorRGB(0,0,0) | |||
| #c.drawString(off_x+5, max_y + off_y - 15 - start_pos_y, ev.start_time.strftime('%H:%M'), 0) | |||
| c.setFont('Helvetica', 12) | |||
| c.drawCentredString(WIDTH/2, max_y + off_y - 35 - start_pos_y, ev.name, 0) | |||
| intervs = ', '.join( [x.slug for x in ev.intervenants] ) | |||
| c.setFont('Helvetica', 10) | |||
| c.drawCentredString(WIDTH/2, max_y + off_y - 55 - start_pos_y, intervs, 0) | |||
| minute = max_y / (9 * 60) | |||
| start_pos_y = ((int(ev.start_time.strftime('%H')) - 10) * 60 + int(ev.start_time.strftime('%M'))) * minute | |||
| stop_pos_y = ((int(ev.end_time.strftime('%H')) - 10) * 60 + int(ev.end_time.strftime('%M'))) * minute | |||
| c.setFillColorRGB(0.98, 0.98, 0.98) | |||
| c.rect(offset[0], max_y + off_y - start_pos_y, max_size[0], start_pos_y - stop_pos_y, fill=1, stroke=1) | |||
| c.setFillColorRGB(0, 0, 0) | |||
| # c.drawString(off_x+5, max_y + off_y - 15 - start_pos_y, ev.start_time.strftime('%H:%M'), 0) | |||
| c.setFont('Helvetica', 12) | |||
| c.drawCentredString(WIDTH / 2, max_y + off_y - 35 - start_pos_y, ev.name, 0) | |||
| intervs = ', '.join([x.slug for x in ev.intervenants]) | |||
| c.setFont('Helvetica', 10) | |||
| c.drawCentredString(WIDTH / 2, max_y + off_y - 55 - start_pos_y, intervs, 0) | |||
| @@ -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") | |||
| @@ -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', | |||