Le repo des sources pour le site web des JM2L
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

badge.py 10 KiB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  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. import io
  9. from pyramid.view import view_config
  10. from .models import DBSession, User
  11. from reportlab.pdfgen import canvas
  12. from reportlab.pdfbase import pdfmetrics
  13. from reportlab.pdfbase.ttfonts import TTFont
  14. from reportlab.lib.units import mm
  15. import qrcode
  16. import subprocess
  17. from .upload import MediaPath
  18. from jm2l.const import CurrentYear
  19. # Create PDF container
  20. EXPIRATION_TIME = 300 # seconds
  21. WIDTH = 85 * mm
  22. HEIGHT = 60 * mm
  23. ICONSIZE = 10 * mm
  24. def JM2L_Logo(canvas, Offset=(0, 0)):
  25. off_x, off_y = Offset
  26. logo_object = canvas.beginText()
  27. logo_object.setFont('Logo', 32)
  28. logo_object.setFillColorRGB(.83, 0, .33)
  29. logo_object.setTextOrigin(off_x + 5, off_y + 17)
  30. logo_object.textLines("JM2L")
  31. canvas.drawText(logo_object)
  32. year_object = canvas.beginText()
  33. year_object.setFont("Helvetica-Bold", 10)
  34. year_object.setFillColorRGB(1, 1, 1)
  35. year_object.setTextRenderMode(0)
  36. year_object.setTextOrigin(off_x + 12, off_y + 35)
  37. year_object.setWordSpace(13)
  38. year_object.textLines(" ".join(str(CurrentYear)))
  39. canvas.drawText(year_object)
  40. def Tiers_Logo(canvas, DispUser, start_pos=None, Offset=(0, 0)):
  41. border = 0
  42. off_x, off_y = Offset
  43. if start_pos is None:
  44. start_pos = (30 * mm, 2)
  45. start_x, start_y = start_pos
  46. max_x, max_y = 34 * mm, 18 * mm
  47. num = 0
  48. canvas.setStrokeColorRGB(0.5, 0.5, 0.5)
  49. list_logos = list()
  50. for thumb in DispUser.tiers:
  51. if thumb.ThumbLinks:
  52. list_logos.append(thumb.ThumbLinks[:3])
  53. # list_logos = list(filter(lambda x: x.ThumbLinks, DispUser.tiers)[:3])
  54. # Should We compute a better positionning for logos ?
  55. DicPos = {}
  56. DicPos[1] = {0: (1. / 2, 1. / 2)}
  57. DicPos[2] = {0: (1. / 3, 1. / 2), 1: (2. / 3, 1. / 2)}
  58. DicPos[3] = {0: (1. / 2, 1. / 4), 1: (1. / 3, 3. / 4), 2: (2. / 3, 3. / 4)}
  59. DicPos[4] = {0: (1. / 3, 1. / 4), 1: (2. / 3, 1. / 4), 2: (1. / 3, 3. / 4),
  60. 3: (2. / 3, 3. / 4)}
  61. DicPos[5] = {0: (1. / 3, 1. / 4), 1: (2. / 3, 1. / 4), 2: (1. / 6, 3. / 4),
  62. 3: (3. / 6, 3. / 4), 4: (5. / 6, 3. / 4)}
  63. DicPos[6] = {0: (1. / 6, 1. / 4), 1: (3. / 6, 1. / 4), 2: (5. / 6, 1. / 4),
  64. 3: (1. / 6, 3. / 4), 4: (3. / 6, 3. / 4), 5: (5. / 6, 3. / 4)}
  65. DicPos[7] = {0: (1. / 6, 1. / 4), 1: (3. / 6, 1. / 4), 2: (5. / 6, 1. / 4),
  66. 3: (1. / 8, 3. / 4), 4: (3. / 8, 3. / 4), 5: (5. / 8, 3. / 4),
  67. 6: (7. / 8, 3. / 4)}
  68. DicPos[8] = {0: (1. / 8, 1. / 4), 1: (3. / 8, 1. / 4), 2: (5. / 8, 1. / 4),
  69. 3: (7. / 8, 1. / 4), 4: (1. / 8, 3. / 4), 5: (3. / 8, 3. / 4),
  70. 6: (5. / 8, 3. / 4), 7: (7. / 8, 3. / 4)}
  71. # draw overall border
  72. # canvas.roundRect(start_x, start_y, max_x, max_y, radius=2, stroke=True)
  73. for tiers in list_logos:
  74. file_name = tiers.ThumbLinks.pop().split("/")[-1]
  75. image_path = "jm2l/upload/images/tiers/%s/%s" % (tiers.slug, file_name)
  76. pos_x = off_x + start_x + DicPos[len(list_logos)][num][0] * max_x - (ICONSIZE + border) / 2
  77. pos_y = off_y + start_y + DicPos[len(list_logos)][num][1] * max_y - (ICONSIZE + border) / 2
  78. canvas.setLineWidth(.1)
  79. if len(list_logos) > 1:
  80. size = ICONSIZE
  81. else:
  82. size = ICONSIZE * 1.5
  83. canvas.drawImage(image_path,
  84. pos_x, pos_y, size, size,
  85. preserveAspectRatio=True,
  86. anchor='c',
  87. mask='auto'
  88. )
  89. # draw icon border
  90. # canvas.roundRect(pos_x, pos_y, ICONSIZE, ICONSIZE, radius=2, stroke=True)
  91. num += 1
  92. def QRCode(DispUser):
  93. qr = qrcode.QRCode(
  94. version=1,
  95. error_correction=qrcode.constants.ERROR_CORRECT_L,
  96. box_size=10,
  97. border=2,
  98. )
  99. # Data of QR code
  100. qr.add_data('http://jm2l.linux-azur.org/user/%s' % DispUser.slug)
  101. qr.make(fit=True)
  102. return qr.make_image()
  103. def one_badge(c, DispUser, Offset=(0, 0)):
  104. # Logo on Top
  105. JM2L_Logo(c, Offset)
  106. off_x, off_y = Offset
  107. c.rect(off_x - 3, off_y - 3, WIDTH + 6, HEIGHT + 6, fill=0, stroke=1)
  108. if DispUser.Staff:
  109. # Staff
  110. c.setFillColorRGB(.83, 0, .33)
  111. c.rect(off_x - 3, off_y + HEIGHT - 30, WIDTH + 6, 33, fill=1, stroke=0)
  112. c.setFillColorRGB(1, 1, 1)
  113. c.setFont('Liberation', 30)
  114. c.drawCentredString(off_x + WIDTH / 2, off_y + HEIGHT - 24, "STAFF")
  115. elif DispUser.is_Intervenant:
  116. # Intervenant
  117. c.setFillColorRGB(.21, .67, .78)
  118. c.rect(off_x - 3, off_y + HEIGHT - 30, WIDTH + 6, 33, fill=1, stroke=0)
  119. c.setFillColorRGB(1, 1, 1)
  120. c.setFont('Liberation', 30)
  121. c.drawCentredString(off_x + WIDTH / 2, off_y + HEIGHT - 24, "Intervenant")
  122. elif DispUser.is_crew:
  123. # Benevole
  124. c.setFillColorRGB(.18, .76, .23)
  125. c.rect(off_x - 3, off_y + HEIGHT - 30, WIDTH + 6, 33, fill=1, stroke=0)
  126. c.setFillColorRGB(1, 1, 1)
  127. c.setFont('Liberation', 30)
  128. c.drawCentredString(off_x + WIDTH / 2, off_y + HEIGHT - 24, "Bénévole")
  129. else:
  130. # Visiteur
  131. c.setFillColorRGB(.8, .8, .8)
  132. c.rect(off_x - 3, off_y + HEIGHT - 30, WIDTH + 6, 33, fill=1, stroke=0)
  133. c.setFillColorRGB(1, 1, 1)
  134. c.setFont('Liberation', 30)
  135. c.drawCentredString(off_x + WIDTH / 2, off_y + HEIGHT - 24, "Visiteur")
  136. c.restoreState()
  137. c.setFont('Liberation', 18)
  138. c.setStrokeColorRGB(0, 0, 0)
  139. c.setFillColorRGB(0, 0, 0)
  140. # Feed Name and SurName
  141. if DispUser.prenom and DispUser.nom and len(DispUser.prenom) + len(DispUser.nom) > 18:
  142. if DispUser.pseudo:
  143. c.drawCentredString(off_x + WIDTH / 2, off_y + HEIGHT / 2 + 0 * mm, "%s" % DispUser.prenom)
  144. # c.setFont('Courier', 17)
  145. c.drawCentredString(off_x + WIDTH / 2, off_y + HEIGHT / 2 - 8 * mm, "%s" % DispUser.nom)
  146. else:
  147. c.drawCentredString(off_x + WIDTH / 2, off_y + HEIGHT / 2 + 4 * mm, "%s" % DispUser.prenom)
  148. # c.setFont('Courier', 17)
  149. c.drawCentredString(off_x + WIDTH / 2, off_y + HEIGHT / 2 - 8 * mm, "%s" % DispUser.nom)
  150. else:
  151. c.drawCentredString(off_x + WIDTH / 2, off_y + HEIGHT / 2 + 0 * mm, "%s %s" % (DispUser.prenom, DispUser.nom))
  152. if DispUser.pseudo:
  153. c.setFont("Helvetica-Oblique", 18)
  154. c.drawCentredString(off_x + WIDTH / 2, off_y + HEIGHT / 2 + 10 * mm, "%s" % DispUser.pseudo)
  155. #  Put QR code to user profile
  156. c.drawInlineImage(QRCode(DispUser),
  157. off_x + WIDTH - 20 * mm - 5, off_y + 5,
  158. 20 * mm, 20 * mm,
  159. preserveAspectRatio=True,
  160. anchor='s')
  161. Tiers_Logo(c, DispUser, None, Offset)
  162. @view_config(route_name='badge_user') # , http_cache=(EXPIRATION_TIME, {'public': True}))
  163. def badge_user(request):
  164. isoutpng = request.params.get('png')
  165. user_slug = request.matchdict.get('user_slug', None)
  166. if user_slug is None or len(user_slug) == 0:
  167. raise HTTPNotFound(u"Cet utilisateur n'a pas été reconnu")
  168. # Query database
  169. DispUser = User.by_slug(user_slug)
  170. if DispUser is None:
  171. raise HTTPNotFound()
  172. # Ok let's generate a PDF Badge
  173. # Register LiberationMono font
  174. ttf_file = "jm2l/static/fonts/LiberationMono-Regular.ttf"
  175. pdfmetrics.registerFont(TTFont("Liberation", ttf_file))
  176. #  Import font
  177. ttf_file_logo = "jm2l/static/fonts/PWTinselLetters.ttf"
  178. pdfmetrics.registerFont(TTFont("Logo", ttf_file_logo))
  179. pdf = io.BytesIO()
  180. out_img = io.BytesIO()
  181. c = canvas.Canvas(pdf, pagesize=(WIDTH, HEIGHT))
  182. c.translate(mm, mm)
  183. # Feed some metadata
  184. c.setCreator("linux-azur.org")
  185. c.setTitle("Badge")
  186. c.saveState()
  187. one_badge(c, DispUser)
  188. out_pdf = MediaPath().get_mediapath("badge", DispUser.uid, 'badge.pdf')
  189. c.showPage()
  190. c.save()
  191. pdf.seek(0)
  192. if isoutpng:
  193. out_png = MediaPath().get_mediapath("badge", DispUser.uid, 'badge.png')
  194. #  Let's generate a png file for website
  195. with open("./%s" % out_pdf, 'wb') as pdff:
  196. pdff.write(pdf.read())
  197. Command = ["convert", "-density", "150x150", out_pdf, out_png]
  198. subprocess.call(Command)
  199. with open("./%s" % out_png, 'rb') as pngfile:
  200. out_img.write(pngfile.read()) # 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. ttf_file = "jm2l/static/fonts/LiberationMono-Regular.ttf"
  216. pdfmetrics.registerFont(TTFont("Liberation", ttf_file))
  217. #  Import font
  218. ttf_file_logo = "jm2l/static/fonts/PWTinselLetters.ttf"
  219. pdfmetrics.registerFont(TTFont("Logo", ttf_file_logo))
  220. pdf = io.BytesIO()
  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. list_user = filter(lambda x: x.is_Intervenant or x.Staff or x.is_crew, Users)
  230. for num, disp_user in enumerate(list_user):
  231. c.saveState()
  232. offsets = (((num - t) % 2) * (WIDTH + 40) + 40, int(((num - t) / 2)) * (HEIGHT + 25) + 40)
  233. one_badge(c, disp_user, 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')