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.
 
 
 
 
 

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