Le repo des sources pour le site web des JM2L
Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.
 
 
 
 
 

280 rader
9.9 KiB

  1. # -*- coding: utf8 -*-
  2. from pyramid.httpexceptions import HTTPNotFound, HTTPForbidden
  3. from pyramid.response import Response
  4. try:
  5. from StringIO import StringIO
  6. except ImportError:
  7. from io import StringIO
  8. from pyramid.view import view_config
  9. from .models import DBSession, User
  10. from reportlab.pdfgen import canvas
  11. from reportlab.pdfbase import pdfmetrics
  12. from reportlab.pdfbase.ttfonts import TTFont
  13. from reportlab.lib.units import mm
  14. import qrcode
  15. import subprocess
  16. from .upload import MediaPath
  17. from jm2l.const import CurrentYear
  18. # Create PDF container
  19. EXPIRATION_TIME = 300 # seconds
  20. WIDTH = 85 * mm
  21. HEIGHT = 60 * mm
  22. ICONSIZE = 10 * mm
  23. def JM2L_Logo(canvas, Offset=(0, 0)):
  24. OffX, OffY = Offset
  25. logoobject = canvas.beginText()
  26. logoobject.setFont('Logo', 32)
  27. logoobject.setFillColorRGB(.83, 0, .33)
  28. logoobject.setTextOrigin(OffX + 5, OffY + 17)
  29. logoobject.textLines("JM2L")
  30. canvas.drawText(logoobject)
  31. yearobject = canvas.beginText()
  32. yearobject.setFont("Helvetica-Bold", 10)
  33. yearobject.setFillColorRGB(1, 1, 1)
  34. yearobject.setTextRenderMode(0)
  35. yearobject.setTextOrigin(OffX + 12, OffY + 35)
  36. yearobject.setWordSpace(13)
  37. yearobject.textLines(" ".join(str(CurrentYear)))
  38. canvas.drawText(yearobject)
  39. def Tiers_Logo(canvas, DispUser, StartPos=None, Offset=(0, 0)):
  40. Border = 0
  41. OffX, OffY = Offset
  42. if StartPos is None:
  43. StartPos = (30 * mm, 2)
  44. StartX, StartY = StartPos
  45. MaxX, MaxY = 34 * mm, 18 * mm
  46. num = 0
  47. canvas.setStrokeColorRGB(0.5, 0.5, 0.5)
  48. Logos = list()
  49. for thumb in DispUser.tiers:
  50. if thumb.ThumbLinks:
  51. Logos.append(thumb.ThumbLinks[:3])
  52. # Logos = list(filter(lambda x: x.ThumbLinks, DispUser.tiers)[:3])
  53. # Should We compute a better positionning for logos ?
  54. DicPos = {}
  55. DicPos[1] = {0: (1. / 2, 1. / 2)}
  56. DicPos[2] = {0: (1. / 3, 1. / 2), 1: (2. / 3, 1. / 2)}
  57. DicPos[3] = {0: (1. / 2, 1. / 4), 1: (1. / 3, 3. / 4), 2: (2. / 3, 3. / 4)}
  58. DicPos[4] = {0: (1. / 3, 1. / 4), 1: (2. / 3, 1. / 4), 2: (1. / 3, 3. / 4),
  59. 3: (2. / 3, 3. / 4)}
  60. DicPos[5] = {0: (1. / 3, 1. / 4), 1: (2. / 3, 1. / 4), 2: (1. / 6, 3. / 4),
  61. 3: (3. / 6, 3. / 4), 4: (5. / 6, 3. / 4)}
  62. DicPos[6] = {0: (1. / 6, 1. / 4), 1: (3. / 6, 1. / 4), 2: (5. / 6, 1. / 4),
  63. 3: (1. / 6, 3. / 4), 4: (3. / 6, 3. / 4), 5: (5. / 6, 3. / 4)}
  64. DicPos[7] = {0: (1. / 6, 1. / 4), 1: (3. / 6, 1. / 4), 2: (5. / 6, 1. / 4),
  65. 3: (1. / 8, 3. / 4), 4: (3. / 8, 3. / 4), 5: (5. / 8, 3. / 4),
  66. 6: (7. / 8, 3. / 4)}
  67. DicPos[8] = {0: (1. / 8, 1. / 4), 1: (3. / 8, 1. / 4), 2: (5. / 8, 1. / 4),
  68. 3: (7. / 8, 1. / 4), 4: (1. / 8, 3. / 4), 5: (3. / 8, 3. / 4),
  69. 6: (5. / 8, 3. / 4), 7: (7. / 8, 3. / 4)}
  70. # draw overall border
  71. # canvas.roundRect(StartX, StartY, MaxX, MaxY, radius=2, stroke=True)
  72. for tiers in Logos:
  73. FileName = tiers.ThumbLinks.pop().split("/")[-1]
  74. ImagePath = "jm2l/upload/images/tiers/%s/%s" % (tiers.slug, FileName)
  75. PosX = OffX + StartX + DicPos[len(Logos)][num][0] * MaxX - (ICONSIZE + Border) / 2
  76. PosY = OffY + StartY + DicPos[len(Logos)][num][1] * MaxY - (ICONSIZE + Border) / 2
  77. canvas.setLineWidth(.1)
  78. if len(Logos) > 1:
  79. size = ICONSIZE
  80. else:
  81. size = ICONSIZE * 1.5
  82. canvas.drawImage(ImagePath,
  83. PosX, PosY, size, size,
  84. preserveAspectRatio=True,
  85. anchor='c',
  86. mask='auto'
  87. )
  88. # draw icon border
  89. # canvas.roundRect(PosX, PosY, ICONSIZE, ICONSIZE, radius=2, stroke=True)
  90. num += 1
  91. def QRCode(DispUser):
  92. qr = qrcode.QRCode(
  93. version=1,
  94. error_correction=qrcode.constants.ERROR_CORRECT_L,
  95. box_size=10,
  96. border=2,
  97. )
  98. # Data of QR code
  99. qr.add_data('http://jm2l.linux-azur.org/user/%s' % DispUser.slug)
  100. qr.make(fit=True)
  101. return qr.make_image()
  102. def one_badge(c, DispUser, Offset=(0, 0)):
  103. # Logo on Top
  104. JM2L_Logo(c, Offset)
  105. OffX, OffY = Offset
  106. c.rect(OffX - 3, OffY - 3, WIDTH + 6, HEIGHT + 6, fill=0, stroke=1)
  107. if DispUser.Staff:
  108. # Staff
  109. c.setFillColorRGB(.83, 0, .33)
  110. c.rect(OffX - 3, OffY + HEIGHT - 30, WIDTH + 6, 33, fill=1, stroke=0)
  111. c.setFillColorRGB(1, 1, 1)
  112. c.setFont('Liberation', 30)
  113. c.drawCentredString(OffX + WIDTH / 2, OffY + HEIGHT - 24, "STAFF")
  114. elif DispUser.is_Intervenant:
  115. # Intervenant
  116. c.setFillColorRGB(.21, .67, .78)
  117. c.rect(OffX - 3, OffY + HEIGHT - 30, WIDTH + 6, 33, fill=1, stroke=0)
  118. c.setFillColorRGB(1, 1, 1)
  119. c.setFont('Liberation', 30)
  120. c.drawCentredString(OffX + WIDTH / 2, OffY + HEIGHT - 24, "Intervenant")
  121. elif DispUser.is_crew:
  122. # Benevole
  123. c.setFillColorRGB(.18, .76, .23)
  124. c.rect(OffX - 3, OffY + HEIGHT - 30, WIDTH + 6, 33, fill=1, stroke=0)
  125. c.setFillColorRGB(1, 1, 1)
  126. c.setFont('Liberation', 30)
  127. c.drawCentredString(OffX + WIDTH / 2, OffY + HEIGHT - 24, "Bénévole")
  128. else:
  129. # Visiteur
  130. c.setFillColorRGB(.8, .8, .8)
  131. c.rect(OffX - 3, OffY + HEIGHT - 30, WIDTH + 6, 33, fill=1, stroke=0)
  132. c.setFillColorRGB(1, 1, 1)
  133. c.setFont('Liberation', 30)
  134. c.drawCentredString(OffX + WIDTH / 2, OffY + HEIGHT - 24, "Visiteur")
  135. c.restoreState()
  136. c.setFont('Liberation', 18)
  137. c.setStrokeColorRGB(0, 0, 0)
  138. c.setFillColorRGB(0, 0, 0)
  139. # Feed Name and SurName
  140. if DispUser.prenom and DispUser.nom and len(DispUser.prenom) + len(DispUser.nom) > 18:
  141. if DispUser.pseudo:
  142. c.drawCentredString(OffX + WIDTH / 2, OffY + HEIGHT / 2 + 0 * mm, "%s" % DispUser.prenom)
  143. # c.setFont('Courier', 17)
  144. c.drawCentredString(OffX + WIDTH / 2, OffY + HEIGHT / 2 - 8 * mm, "%s" % DispUser.nom)
  145. else:
  146. c.drawCentredString(OffX + WIDTH / 2, OffY + HEIGHT / 2 + 4 * mm, "%s" % DispUser.prenom)
  147. # c.setFont('Courier', 17)
  148. c.drawCentredString(OffX + WIDTH / 2, OffY + HEIGHT / 2 - 8 * mm, "%s" % DispUser.nom)
  149. else:
  150. c.drawCentredString(OffX + WIDTH / 2, OffY + HEIGHT / 2 + 0 * mm, "%s %s" % (DispUser.prenom, DispUser.nom))
  151. if DispUser.pseudo:
  152. c.setFont("Helvetica-Oblique", 18)
  153. c.drawCentredString(OffX + WIDTH / 2, OffY + HEIGHT / 2 + 10 * mm, "%s" % DispUser.pseudo)
  154. #  Put QR code to user profile
  155. c.drawInlineImage(QRCode(DispUser), \
  156. OffX + WIDTH - 20 * mm - 5, OffY + 5, \
  157. 20 * mm, 20 * mm, \
  158. preserveAspectRatio=True, \
  159. anchor='s')
  160. Tiers_Logo(c, DispUser, None, Offset)
  161. @view_config(route_name='badge_user') # , http_cache=(EXPIRATION_TIME, {'public': True}))
  162. def badge_user(request):
  163. isoutpng = request.params.get('png')
  164. user_slug = request.matchdict.get('user_slug', None)
  165. if user_slug is None or len(user_slug) == 0:
  166. raise HTTPNotFound(u"Cet utilisateur n'a pas été reconnu")
  167. # Query database
  168. DispUser = User.by_slug(user_slug)
  169. if DispUser is None:
  170. raise HTTPNotFound()
  171. # Ok let's generate a PDF Badge
  172. # Register LiberationMono font
  173. ttfFile = "jm2l/static/fonts/LiberationMono-Regular.ttf"
  174. pdfmetrics.registerFont(TTFont("Liberation", ttfFile))
  175. #  Import font
  176. ttfFile_Logo = "jm2l/static/fonts/PWTinselLetters.ttf"
  177. pdfmetrics.registerFont(TTFont("Logo", ttfFile_Logo))
  178. pdf = StringIO()
  179. out_img = StringIO()
  180. c = canvas.Canvas(pdf, pagesize=(WIDTH, HEIGHT))
  181. c.translate(mm, mm)
  182. # Feed some metadata
  183. c.setCreator("linux-azur.org")
  184. c.setTitle("Badge")
  185. c.saveState()
  186. one_badge(c, DispUser)
  187. OutPDF = MediaPath().get_mediapath("badge", DispUser.uid, 'badge.pdf')
  188. c.showPage()
  189. c._filename = OutPDF
  190. c.save()
  191. pdf.seek(0)
  192. if isoutpng:
  193. OutPNG = MediaPath().get_mediapath("badge", DispUser.uid, 'badge.png')
  194. #  Let's generate a png file for website
  195. with open("./%s" % OutPDF, 'wb') as pdff:
  196. pdff.write(bytes(pdf.read(), 'utf8')) # .encode('utf8'))
  197. Command = ["convert", "-density", "150x150", OutPDF, OutPNG]
  198. subprocess.call(Command)
  199. with open("./%s" % OutPNG, 'r') as pngfile:
  200. out_img.write(bytes(pngfile.read(), 'utf8')) # bytes(pngfile.read(), "utf8"))
  201. out_img.seek(0)
  202. return Response(app_iter=out_img, content_type='image/png')
  203. else:
  204. return Response(app_iter=pdf, content_type='application/pdf')
  205. @view_config(route_name='all_badges')
  206. def planche_badge(request):
  207. if request.user is None:
  208. # Don't answer to users that aren't logged
  209. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  210. # Query database about selected Year.
  211. Users = DBSession.query(User)
  212. # .join(User_Event)\
  213. # .filter(User_Event.year_uid == year)
  214. # Register LiberationMono font
  215. ttfFile = "jm2l/static/fonts/LiberationMono-Regular.ttf"
  216. pdfmetrics.registerFont(TTFont("Liberation", ttfFile))
  217. #  Import font
  218. ttfFile_Logo = "jm2l/static/fonts/PWTinselLetters.ttf"
  219. pdfmetrics.registerFont(TTFont("Logo", ttfFile_Logo))
  220. pdf = StringIO.StringIO()
  221. FULLWIDTH = 210 * mm
  222. FULLHEIGHT = 297 * mm
  223. c = canvas.Canvas(pdf, pagesize=(FULLWIDTH, FULLHEIGHT))
  224. c.translate(mm, mm)
  225. # Feed some metadata
  226. c.setCreator("linux-azur.org")
  227. c.setTitle("Badge")
  228. t = 0
  229. ListUser = filter(lambda x: x.is_Intervenant or x.Staff or x.is_crew, Users)
  230. for num, DispUser in enumerate(ListUser):
  231. c.saveState()
  232. Offsets = (((num - t) % 2) * (WIDTH + 40) + 40, ((num - t) / 2) * (HEIGHT + 25) + 40)
  233. one_badge(c, DispUser, Offsets)
  234. if num % 8 == 7:
  235. t = num + 1
  236. c.showPage()
  237. c.showPage()
  238. c.save()
  239. pdf.seek(0)
  240. return Response(app_iter=pdf, content_type='application/pdf')