#69. Add basic License support.
[booki.git] / lib / booki / editor / sputnik.py
blob6dd8ae1696efc5cb50bbd35588abfc8681b2e419
1 import redis, time
2 import simplejson
4 # must fix this rcon issue somehow.
5 # this is stupid but will work for now
7 rcon = redis.Redis()
8 #rcon.connect()
10 def hasChannel(channelName):
11 global rcon
13 return rcon.sismember("sputnik:channels", channelName)
15 def createChannel(channelName):
16 global rcon
18 if not hasChannel(channelName):
19 rcon.sadd("sputnik:channels", channelName)
21 return True
23 def removeChannel(channelName):
24 global rcon
26 return rcon.srem("sputnik:channels", channelName)
28 def addClientToChannel(channelName, client):
29 global rcon
31 rcon.sadd("ses:%s:channels" % client, channelName)
33 rcon.sadd("sputnik:channel:%s" % channelName, client)
35 def removeClientFromChannel(channelName, client):
36 global rcon
38 return rcon.srem("sputnik:channel:%s" % channelName, client)
40 def addMessageToChannel(request, channelName, message, myself = False ):
41 global rcon
43 clnts = rcon.smembers("sputnik:channel:%s" % channelName)
45 message["channel"] = channelName
46 message["clientID"] = request.clientID
48 for c in clnts:
49 if not myself and c == request.sputnikID:
50 continue
52 rcon.push( "ses:%s:messages" % c, simplejson.dumps(message), tail = True)
54 def removeClient(clientName):
55 global rcon
57 for chnl in rcon.smembers("ses:%s:channels" % clientName):
58 removeClientFromChannel(chnl, clientName)
59 rcon.srem("ses:%s:channels" % clientName, chnl)
61 rcon.delete("ses:%s:last_access" % clientName)
63 # TODO
64 # also, i should delete all messages
67 ## treba viditi shto opcenito sa onim
69 def booki_main(request, message):
70 global rcon
72 rcon.connect()
74 ret = {}
75 if message["command"] == "ping":
76 addMessageToChannel(request, "/booki/", {})
78 if message["command"] == "disconnect":
79 pass
81 if message["command"] == "connect":
82 # this is where we have problems
83 if not rcon.exists("sputnik:client_id"):
84 rcon.set("sputnik:client_id", 0)
86 clientID = rcon.incr("sputnik:client_id")
87 ret["clientID"] = clientID
88 request.sputnikID = "%s:%s" % (request.session.session_key, clientID)
90 # subscribe to this channels
91 for chnl in message["channels"]:
92 if not hasChannel(chnl):
93 createChannel(chnl)
95 addClientToChannel(chnl, request.sputnikID)
97 # set our last access
98 rcon.set("ses:%s:last_access" % request.sputnikID, time.time())
100 return ret
104 def booki_chat(request, message, projectid, bookid):
105 if message["command"] == "message_send":
106 addMessageToChannel(request, "/chat/%s/%s/" % (projectid, bookid), {"command": "message_received", "from": request.user.username, "message": message["message"]})
107 return {}
109 return {}
111 # remove all the copy+paste code
114 # getChapters
116 def getTOCForBook(book):
117 from booki.editor import models
119 results = []
121 for chap in list(models.BookToc.objects.filter(book=book).order_by("-weight")):
122 # is it a section or chapter
123 if chap.chapter:
124 results.append((chap.chapter.id, chap.chapter.title, chap.chapter.url_title, chap.typeof, chap.chapter.status.id))
125 else:
126 results.append(('s%s' % chap.id, chap.name, chap.name, chap.typeof))
128 return results
131 # booki_book
134 def getHoldChapters(book_id):
135 from django.db import connection, transaction
136 cursor = connection.cursor()
137 # wgere chapter_id is NULL that is the hold Chapter
138 cursor.execute("select editor_chapter.id, editor_chapter.title, editor_chapter.url_title, editor_booktoc.chapter_id, editor_chapter.status_id from editor_chapter left outer join editor_booktoc on (editor_chapter.id=editor_booktoc.chapter_id) where editor_chapter.book_id=%s;", (book_id, ))
140 chapters = []
141 for row in cursor.fetchall():
142 if row[-2] == None:
143 chapters.append((row[0], row[1], row[2], 1, row[4]))
145 return chapters
148 def getAttachments(book):
149 from booki.editor import models
150 import os.path
151 import Image
153 def _getDimension(att):
154 if att.attachment.name.endswith(".jpg"):
155 try:
156 im = Image.open(att.attachment.name)
157 return im.size
158 except:
159 return (0, 0)
160 return None
163 attachments = [{"id": att.id, "dimension": _getDimension(att), "status": att.status.id, "name": os.path.split(att.attachment.name)[1], "size": att.attachment.size} for att in models.Attachment.objects.filter(book=book)]
165 return attachments
168 def booki_book(request, message, projectid, bookid):
169 from booki.editor import models
171 ## init_editor
172 if message["command"] == "init_editor":
174 project = models.Project.objects.get(id=projectid)
175 book = models.Book.objects.get(project=project, id=bookid)
177 ## get chapters
179 chapters = getTOCForBook(book)
180 holdChapters = getHoldChapters(bookid)
182 ## get users
184 def vidi(a):
185 if a == request.sputnikID:
186 return "<b>%s</b>" % a
187 return a
189 users = [vidi(m) for m in list(rcon.smembers("sputnik:channel:%s" % message["channel"]))]
191 ## get workflow statuses
193 statuses = [(status.id, status.name) for status in models.ProjectStatus.objects.filter(project=project).order_by("-weight")]
194 ## get attachments
196 attachments = getAttachments(book)
198 ## get metadata
200 metadata = [{'name': v.name, 'value': v.getValue()} for v in models.Info.objects.filter(book=book)]
202 ## notify others
203 addMessageToChannel(request, "/chat/%s/%s/" % (projectid, bookid), {"command": "user_joined", "user_joined": request.user.username}, myself = False)
205 ## get licenses
207 licenses = [(elem.abbrevation, elem.name) for elem in models.License.objects.all().order_by("name")]
209 return {"licenses": licenses, "chapters": chapters, "metadata": metadata, "hold": holdChapters, "users": users, "statuses": statuses, "attachments": attachments}
211 ## attachments list
212 if message["command"] == "attachments_list":
213 project = models.Project.objects.get(id=projectid)
214 book = models.Book.objects.get(project=project, id=bookid)
216 attachments = getAttachments(book)
218 return {"attachments": attachments}
220 ## chapter_status
221 if message["command"] == "chapter_status":
222 addMessageToChannel(request, "/booki/book/%s/%s/" % (projectid, bookid), {"command": "chapter_status", "chapterID": message["chapterID"], "status": message["status"], "username": request.user.username})
223 return {}
225 ## chapter_save
226 if message["command"] == "chapter_save":
227 chapter = models.Chapter.objects.get(id=int(message["chapterID"]))
228 chapter.content = message["content"];
229 chapter.save()
231 addMessageToChannel(request, "/chat/%s/%s/" % (projectid, bookid), {"command": "message_info", "from": request.user.username, "message": 'User %s has saved chapter "%s".' % (request.user.username, chapter.title)}, myself=True)
233 addMessageToChannel(request, "/booki/book/%s/%s/" % (projectid, bookid), {"command": "chapter_status", "chapterID": message["chapterID"], "status": "normal", "username": request.user.username})
235 return {}
237 ## chapter_rename
238 if message["command"] == "chapter_rename":
239 chapter = models.Chapter.objects.get(id=int(message["chapterID"]))
240 oldTitle = chapter.title
241 chapter.title = message["chapter"];
242 chapter.save()
244 addMessageToChannel(request, "/chat/%s/%s/" % (projectid, bookid), {"command": "message_info", "from": request.user.username, "message": 'User %s has renamed chapter "%s" to "%s".' % (request.user.username, oldTitle, message["chapter"])}, myself=True)
246 addMessageToChannel(request, "/booki/book/%s/%s/" % (projectid, bookid), {"command": "chapter_status", "chapterID": message["chapterID"], "status": "normal", "username": request.user.username})
248 addMessageToChannel(request, "/booki/book/%s/%s/" % (projectid, bookid), {"command": "chapter_rename", "chapterID": message["chapterID"], "chapter": message["chapter"]})
250 return {}
252 ## chapters_changed
253 if message["command"] == "chapters_changed":
254 lst = [chap[5:] for chap in message["chapters"]]
255 lstHold = [chap[5:] for chap in message["hold"]]
257 project = models.Project.objects.get(id=projectid)
258 book = models.Book.objects.get(project=project, id=bookid)
260 weight = len(lst)
262 for chap in lst:
263 if chap[0] == 's':
264 m = models.BookToc.objects.get(id__exact=int(chap[1:]))
265 m.weight = weight
266 m.save()
267 else:
268 try:
269 m = models.BookToc.objects.get(chapter__id__exact=int(chap))
270 m.weight = weight
271 m.save()
272 except:
273 chptr = models.Chapter.objects.get(id__exact=int(chap))
274 m = models.BookToc(book = book,
275 name = "SOMETHING",
276 chapter = chptr,
277 weight = weight,
278 typeof=1)
279 m.save()
281 weight -= 1
283 if message["kind"] == "remove":
284 if type(message["chapter_id"]) == type(u' ') and message["chapter_id"][0] == 's':
285 m = models.BookToc.objects.get(id__exact=message["chapter_id"][1:])
286 m.delete()
287 else:
288 m = models.BookToc.objects.get(chapter__id__exact=int(message["chapter_id"]))
289 m.delete()
291 # addMessageToChannel(request, "/chat/%s/%s/" % (projectid, bookid), {"command": "message_info", "from": request.user.username, "message": 'User %s has rearranged chapters.' % request.user.username})
293 addMessageToChannel(request, "/booki/book/%s/%s/" % (projectid, bookid), {"command": "chapters_changed", "ids": lst, "hold_ids": lstHold, "kind": message["kind"], "chapter_id": message["chapter_id"]})
294 return {}
296 ## get_users
297 if message["command"] == "get_users":
298 res = {}
299 def vidi(a):
300 if a == request.sputnikID:
301 return "!%s!" % a
302 return a
304 res["users"] = [vidi(m) for m in list(rcon.smembers("sputnik:channel:%s" % message["channel"]))]
305 return res
307 ## get_chapter
308 if message["command"] == "get_chapter":
309 res = {}
311 chapter = models.Chapter.objects.get(id=int(message["chapterID"]))
312 res["title"] = chapter.title
313 res["content"] = chapter.content
315 addMessageToChannel(request, "/booki/book/%s/%s/" % (projectid, bookid), {"command": "chapter_status", "chapterID": message["chapterID"], "status": "edit", "username": request.user.username})
317 return res
319 ## chapter_split
320 if message["command"] == "chapter_split":
321 project = models.Project.objects.get(id=projectid)
322 book = models.Book.objects.get(project=project, id=bookid)
324 allChapters = []
326 try:
327 mainChapter = models.BookToc.objects.get(book=book, chapter__id__exact=message["chapterID"])
328 except:
329 mainChapter = None
331 import datetime
332 from django.template.defaultfilters import slugify
334 if mainChapter:
335 allChapters = [chap for chap in models.BookToc.objects.filter(book=book).order_by("-weight")]
336 initialPosition = len(allChapters)-mainChapter.weight
337 #allChapters.remove(mainChapter)
338 else:
339 initialPosition = 0
341 s = models.ProjectStatus.objects.filter(project=project).order_by("weight")[0]
343 n = 0
344 for chap in message["chapters"]:
345 chapter = models.Chapter(book = book,
346 url_title = slugify(chap[0]),
347 title = chap[0],
348 status = s,
349 content = chap[1],
350 created = datetime.datetime.now(),
351 modified = datetime.datetime.now())
352 chapter.save()
354 if mainChapter:
355 m = models.BookToc(book = book,
356 chapter = chapter,
357 name = chap[0],
358 weight = 0,
359 typeof = 1)
360 m.save()
361 allChapters.insert(initialPosition+n, m)
363 n += 1
365 addMessageToChannel(request, "/chat/%s/%s/" % (projectid, bookid), {"command": "message_info", "from": request.user.username, "message": 'User %s has split chapter "%s".' % (request.user.username, mainChapter.chapter.title)}, myself=True)
368 mainChapter.chapter.delete()
370 n = len(allChapters)
371 for chap in allChapters:
372 try:
373 chap.weight = n
374 chap.save()
375 n -= 1
376 except:
377 pass
379 ## get chapters
381 chapters = getTOCForBook(book)
382 holdChapters = getHoldChapters(bookid)
387 addMessageToChannel(request, "/booki/book/%s/%s/" % (projectid, bookid), {"command": "chapter_split", "chapterID": message["chapterID"], "chapters": chapters, "hold": holdChapters, "username": request.user.username}, myself = True)
390 return {}
392 ## create_chapter
393 if message["command"] == "create_chapter":
394 from booki.editor import models
396 import datetime
397 project = models.Project.objects.get(id=projectid)
398 book = models.Book.objects.get(project=project, id=bookid)
400 from django.template.defaultfilters import slugify
402 url_title = slugify(message["chapter"])
404 # here i should probably set it to default project status
405 s = models.ProjectStatus.objects.filter(project=project).order_by("weight")[0]
407 chapter = models.Chapter(book = book,
408 url_title = url_title,
409 title = message["chapter"],
410 status = s,
411 content = '<h1>%s</h1>' % message["chapter"],
412 created = datetime.datetime.now(),
413 modified = datetime.datetime.now())
414 chapter.save()
416 # c = models.BookToc(book = book,
417 # name = message["chapter"],
418 # chapter = chapter,
419 # weight = 0,
420 # typeof=1)
421 # c.save()
423 result = (chapter.id, chapter.title, chapter.url_title, 1, s.id)
425 addMessageToChannel(request, "/chat/%s/%s/" % (projectid, bookid), {"command": "message_info", "from": request.user.username, "message": 'User %s has created new chapter "%s".' % (request.user.username, message["chapter"])}, myself=True)
428 addMessageToChannel(request, "/booki/book/%s/%s/" % (projectid, bookid), {"command": "chapter_create", "chapter": result}, myself = True)
430 return {}
432 ## publish_book
433 if message["command"] == "publish_book":
434 project = models.Project.objects.get(id=projectid)
435 book = models.Book.objects.get(project=project, id=bookid)
437 addMessageToChannel(request, "/chat/%s/%s/" % (projectid, bookid), {"command": "message_info", "from": request.user.username, "message": '"%s" is being published.' % (book.title, )}, myself=True)
439 import urllib2
440 f = urllib2.urlopen("http://objavi.flossmanuals.net/objavi.cgi?book=%s&project=%s&mode=epub&server=booki.flossmanuals.net&destination=archive.org" % (book.url_title, project.url_name))
441 ta = f.read()
442 lst = ta.split("\n")
443 dta = lst[0]
444 dtas3 = lst[1]
446 addMessageToChannel(request, "/chat/%s/%s/" % (projectid, bookid), {"command": "message_info", "from": request.user.username, "message": '"%s" is published.' % (book.title, )}, myself=True)
448 return {"dtaall": ta, "dta": dta, "dtas3": dtas3}
450 ## create_section
451 if message["command"] == "create_section":
452 from booki.editor import models
454 import datetime
455 project = models.Project.objects.get(id=projectid)
456 book = models.Book.objects.get(project=project, id=bookid)
458 c = models.BookToc(book = book,
459 name = message["chapter"],
460 chapter = None,
461 weight = 0,
462 typeof=0)
463 c.save()
465 result = ("s%s" % c.id, c.name, None, c.typeof)
468 addMessageToChannel(request, "/chat/%s/%s/" % (projectid, bookid), {"command": "message_info", "from": request.user.username, "message": 'User %s has created new section "%s".' % (request.user.username, message["chapter"])}, myself=True)
470 addMessageToChannel(request, "/booki/book/%s/%s/" % (projectid, bookid), {"command": "chapter_create", "chapter": result, "typeof": c.typeof}, myself = True)
472 return {}
475 return {}