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.
 
 
 
 
 

266 lines
9.4 KiB

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