def send_message_mp(author, n_topic, text, send_by_mail=True, direct=False, hat=None): """ Send a post in an MP. Most of the param are obvious, excepted : * direct : send a mail directly without mp (ex : ban members who wont connect again) * leave : the author leave the conversation (usefull for the bot : it wont read the response a member could send) """ # Getting the position of the post if n_topic.last_message is None: pos = 1 else: pos = n_topic.last_message.position_in_topic + 1 # Add the first message post = PrivatePost() post.privatetopic = n_topic post.author = author post.text = text post.text_html = emarkdown(text) post.pubdate = datetime.now() post.position_in_topic = pos post.hat = hat post.save() n_topic.last_message = post n_topic.save() if not direct: signals.new_content.send(sender=post.__class__, instance=post, by_email=send_by_mail) if send_by_mail and direct: subject = '{} : {}'.format(settings.ZDS_APP['site']['literal_name'], n_topic.title) from_email = '{} <{}>'.format( settings.ZDS_APP['site']['literal_name'], settings.ZDS_APP['site']['email_noreply']) for recipient in n_topic.participants.values_list('email', flat=True): message_html = render_to_string('email/direct.html', {'msg': emarkdown(text)}) message_txt = render_to_string('email/direct.txt', {'msg': text}) msg = EmailMultiAlternatives(subject, message_txt, from_email, [recipient]) msg.attach_alternative(message_html, 'text/html') try: msg.send() except Exception as e: logger.exception('Message was not sent to %s due to %s', recipient, e) return n_topic
def test_get_description(self): """ test the return value of description """ emarkdown(self.post3.text) ref = emarkdown(self.post3.text) posts = self.postfeed.items(obj={'tag': self.tag2.pk}) ret = self.postfeed.item_description(item=posts[0]) self.assertEqual(ret, ref)
def send_message_mp( author, n_topic, text, send_by_mail=True, direct=False): """ Send a post in an MP. Most of the param are obvious, excepted : * direct : send a mail directly without mp (ex : ban members who wont connect again) * leave : the author leave the conversation (usefull for the bot : it wont read the response a member could send) """ # Getting the position of the post if n_topic.last_message is None: pos = 1 else: pos = n_topic.last_message.position_in_topic + 1 # Add the first message post = PrivatePost() post.privatetopic = n_topic post.author = author post.text = text post.text_html = emarkdown(text) post.pubdate = datetime.now() post.position_in_topic = pos post.save() n_topic.last_message = post n_topic.save() # send email if send_by_mail: if direct: subject = u"{} : {}".format(settings.ZDS_APP['site']['litteral_name'], n_topic.title) from_email = u"{} <{}>".format(settings.ZDS_APP['site']['litteral_name'], settings.ZDS_APP['site']['email_noreply']) for part in n_topic.participants.all(): message_html = render_to_string('email/direct.html', {'msg': emarkdown(text)}) message_txt = render_to_string('email/direct.txt', {'msg': text}) msg = EmailMultiAlternatives(subject, message_txt, from_email, [part.email]) msg.attach_alternative(message_html, "text/html") try: msg.send() except: msg = None else: for part in n_topic.participants.all(): send_email(author, n_topic, part, pos) send_email(author, n_topic, n_topic.author, pos) return n_topic
def send_message_mp( author, n_topic, text, send_by_mail=True, direct=False, hat=None): """ Send a post in an MP. Most of the param are obvious, excepted : * direct : send a mail directly without mp (ex : ban members who wont connect again) * leave : the author leave the conversation (usefull for the bot : it wont read the response a member could send) """ # Getting the position of the post if n_topic.last_message is None: pos = 1 else: pos = n_topic.last_message.position_in_topic + 1 # Add the first message post = PrivatePost() post.privatetopic = n_topic post.author = author post.text = text post.text_html = emarkdown(text) post.pubdate = datetime.now() post.position_in_topic = pos post.hat = hat post.save() n_topic.last_message = post n_topic.save() if not direct: signals.new_content.send(sender=post.__class__, instance=post, by_email=send_by_mail) if send_by_mail and direct: subject = '{} : {}'.format(settings.ZDS_APP['site']['literal_name'], n_topic.title) from_email = '{} <{}>'.format(settings.ZDS_APP['site']['literal_name'], settings.ZDS_APP['site']['email_noreply']) for recipient in n_topic.participants.values_list('email', flat=True): message_html = render_to_string('email/direct.html', {'msg': emarkdown(text)}) message_txt = render_to_string('email/direct.txt', {'msg': text}) msg = EmailMultiAlternatives(subject, message_txt, from_email, [recipient]) msg.attach_alternative(message_html, 'text/html') try: msg.send() except Exception as e: logger.exception('Message was not sent to %s due to %s', recipient, e) return n_topic
def index_container(container, search_index_content, archive): """Index a container. :param container: container to index :type container: Container :param search_index_content: parent index :type search_index_content: SearchIndexContent :param archive: zip archive containing the content :type archive: zipfile.ZipFile """ search_index_container = SearchIndexContainer() search_index_container.search_index_content = search_index_content search_index_container.title = container.title search_index_container.url_to_redirect = container.get_absolute_url_online( ) # index introduction and conclusion: if container.introduction: try: introduction_html = emarkdown( get_file_content_in_zip(archive, container.introduction)) all_html = introduction_html search_index_container.introduction = filter_text( introduction_html) except KeyError: pass if container.conclusion: try: conclusion_html = emarkdown( get_file_content_in_zip(archive, container.conclusion)) all_html = u'{}{}'.format(all_html, conclusion_html) search_index_container.conclusion = filter_text(conclusion_html) except KeyError: pass if all_html != u'': search_index_container.keywords = filter_keyword(all_html) # index children: search_index_container.level = 'part' for child in container.children: if isinstance(child, Extract): search_index_container.level = 'chapter' # only a chapter can contain extracts index_extract(child, search_index_content, archive) else: index_container(child, search_index_content, archive) search_index_container.save()
def index_extract(extract, search_index_content, archive): """Index an extract. :param extract: extact to index :type extract: Extract :param search_index_content: parent index :type search_index_content: SearchIndexContent :param archive: zip archive containing the content :type archive: zipfile.ZipFile """ search_index_extract = SearchIndexExtract() search_index_extract.search_index_content = search_index_content search_index_extract.title = extract.title search_index_extract.url_to_redirect = extract.get_absolute_url_online() html = u'' if extract.text: try: html = emarkdown(get_file_content_in_zip(archive, extract.text)) except KeyError: pass if html: search_index_extract.extract_content = filter_text(html) search_index_extract.keywords = filter_keyword(html) search_index_extract.save()
def create_topic(author, forum, title, subtitle, text, key): """create topic in forum""" (tags, title_only) = get_tag_by_title(title[:80]) # Creating the thread n_topic = Topic() n_topic.forum = forum n_topic.title = title_only n_topic.subtitle = subtitle n_topic.pubdate = datetime.now() n_topic.author = author n_topic.key = key n_topic.save() n_topic.add_tags(tags) n_topic.save() # Add the first message post = Post() post.topic = n_topic post.author = author post.text = text post.text_html = emarkdown(text) post.pubdate = datetime.now() post.position = 1 post.save() n_topic.last_message = post n_topic.save() follow(n_topic, user=author) return n_topic
def load_comment_tutorial(cli, size, fake): """ Load tutorial's comments """ nb_avg_posts = size * 20 cli.stdout.write( u"Nombres de messages à poster en moyenne dans un tutoriel : {}". format(nb_avg_posts)) tps1 = time.time() nb_tutorials = Tutorial.objects.filter(sha_public__isnull=False).count() tutorials = list(Tutorial.objects.filter(sha_public__isnull=False).all()) nb_users = User.objects.count() profiles = list(Profile.objects.all()) for i in range(0, nb_tutorials): nb = randint(0, nb_avg_posts * 2) for j in range(0, nb): post = NoteFactory(tutorial=tutorials[i], author=profiles[j % nb_users].user, position=j + 1) post.text = fake.paragraph(nb_sentences=5, variable_nb_sentences=True) post.text_html = emarkdown(post.text) post.save() sys.stdout.write(" Tuto {}/{} \tComment {}/{} \r".format( i + 1, nb_tutorials, j + 1, nb)) sys.stdout.flush() tps2 = time.time() cli.stdout.write(u"\nFait en {} sec".format(tps2 - tps1))
def perform_update(self, instance, data, hat=None): instance.hat = hat instance.text = data.get('text') instance.text_html = emarkdown(data.get('text')) instance.update = datetime.now() instance.save() return instance
def load_posts(cli, size, fake): """ Load posts """ nb_avg_posts_in_topic = size * 10 cli.stdout.write(u"Nombres de messages à poster en moyenne dans un sujet : {}".format(nb_avg_posts_in_topic)) tps1 = time.time() nb_topics = Topic.objects.count() if nb_topics == 0: cli.stdout.write(u"Il n'y a aucun topic actuellement. " u"Vous devez rajouter les topics dans vos fixtures (topic)") else: topics = list(Topic.objects.all()) nb_users = User.objects.count() if nb_users == 0: cli.stdout.write(u"Il n'y a aucun membre actuellement. " u"Vous devez rajouter les membres dans vos fixtures (member)") else: profiles = list(Profile.objects.all()) for i in range(0, nb_topics): nb_posts = randint(0, nb_avg_posts_in_topic * 2) + 1 for j in range(1, nb_posts): post = PostFactory(topic=topics[i], author=profiles[j % nb_users].user, position=j + 1) post.text = fake.paragraph(nb_sentences=5, variable_nb_sentences=True) post.text_html = emarkdown(post.text) if int(nb_posts * 0.3) > 0: if j % int(nb_posts * 0.3) == 0: post.is_useful = True post.save() sys.stdout.write(" Topic {}/{} \tPost {}/{} \r".format(i + 1, nb_topics, j + 1, nb_posts)) sys.stdout.flush() tps2 = time.time() cli.stdout.write(u"\nFait en {} sec".format(tps2 - tps1))
def load_comment_content(cli, size, fake): """ Load content's comments """ nb_avg_posts = size * 10 cli.stdout.write(u"Nombres de messages à poster en moyenne : {}".format(nb_avg_posts)) tps1 = time.time() contents = list(PublishableContent.objects.filter(sha_public__isnull=False)) nb_contents = len(contents) profiles = list(Profile.objects.all()) nb_users = len(profiles) for i in range(0, nb_contents): nb_posts = randint(0, nb_avg_posts * 2) post = None for j in range(0, nb_posts): post = ContentReactionFactory( related_content=contents[i], author=profiles[j % nb_users].user, position=j + 1) post.text = fake.paragraph(nb_sentences=5, variable_nb_sentences=True) post.text_html = emarkdown(post.text) post.save() sys.stdout.write("Contenu {}/{} \tCommentaire {}/{} \r". format(i + 1, nb_contents, j + 1, nb_posts)) sys.stdout.flush() contents[i].last_note = post contents[i].save() tps2 = time.time() cli.stdout.write(u"\nFait en {:.3f} sec".format(tps2 - tps1))
def perform_update(self, instance, data, hat=None): instance.hat = hat instance.text = data.get("text") instance.text_html = emarkdown(data.get("text")) instance.update = datetime.now() instance.save() return instance
def _dump_html(self, file_path, content, db_object): try: with file_path.open('w', encoding='utf-8') as f: f.write(emarkdown(content, db_object.js_support)) except (UnicodeError, UnicodeEncodeError): raise FailureDuringPublication( _("Une erreur est survenue durant la publication de l'introduction de « {} »," ' vérifiez le code markdown').format(self.title))
def unlock_topic(topic, msg): topic.is_locked = False main = Post.objects.filter(topic__pk=topic.pk, position=1).first() main.text = msg main.text_html = emarkdown(msg) main.editor = topic.author main.update = datetime.now() main.save() topic.save()
def MEP(article, sha): #convert markdown file to html file repo = Repo(article.get_path()) manifest = get_blob(repo.commit(sha).tree, 'manifest.json') article_version = json.loads(manifest) md_file_contenu = get_blob(repo.commit(sha).tree, article_version['text']) html_file = open(os.path.join(article.get_path(), article_version['text']+'.html'), "w") html_file.write(emarkdown(md_file_contenu)) html_file.close()
def edit_post(request): """Edit the given user's post.""" try: post_pk = request.GET["message"] except KeyError: raise Http404 post = get_object_or_404(PrivatePost, pk=post_pk) # Only edit last private post tp = get_object_or_404(PrivateTopic, pk=post.privatetopic.pk) last = get_object_or_404(PrivatePost, pk=tp.last_message.pk) if not last.pk == post.pk: raise PermissionDenied g_topic = None if post.position_in_topic >= 1: g_topic = get_object_or_404(PrivateTopic, pk=post.privatetopic.pk) # Making sure the user is allowed to do that. Author of the post # must to be the user logged. if post.author != request.user: raise PermissionDenied if request.method == "POST": if "text" not in request.POST: # if preview mode return on if "preview" in request.POST: return redirect(reverse("zds.mp.views.edit_post") + "?message=" + str(post_pk)) # disallow send mp else: raise PermissionDenied # Using the preview button if "preview" in request.POST: form = PrivatePostForm(g_topic, request.user, initial={"text": request.POST["text"]}) form.helper.form_action = reverse("zds.mp.views.edit_post") + "?message=" + str(post_pk) return render_template("mp/post/edit.html", {"post": post, "topic": g_topic, "form": form}) # The user just sent data, handle them post.text = request.POST["text"] post.text_html = emarkdown(request.POST["text"]) post.update = datetime.now() post.save() return redirect(post.get_absolute_url()) else: form = PrivatePostForm(g_topic, request.user, initial={"text": post.text}) form.helper.form_action = reverse("zds.mp.views.edit_post") + "?message=" + str(post_pk) return render_template("mp/post/edit.html", {"post": post, "topic": g_topic, "text": post.text, "form": form})
def MEP(article, sha): # convert markdown file to html file repo = Repo(article.get_path()) manifest = get_blob(repo.commit(sha).tree, 'manifest.json') article_version = json_reader.loads(manifest) md_file_contenu = get_blob(repo.commit(sha).tree, article_version['text']) html_file = open( os.path.join(article.get_path(), article_version['text'] + '.html'), "w") html_file.write(emarkdown(md_file_contenu)) html_file.close()
def send_post(topic, text): post = Post() post.topic = topic post.author = topic.author post.text = text post.text_html = emarkdown(text) post.pubdate = datetime.now() post.position = topic.last_message.position + 1 post.save() topic.last_message = post topic.save()
def __generate_topic_and_post(cli, fake, nb_avg_posts_in_topic, nb_topics, nb_users, topics, tps1): profiles = list(Profile.objects.all()) for topic_index in range(0, nb_topics): nb_posts = randint(0, nb_avg_posts_in_topic * 2) + 1 for post_index in range(1, nb_posts): post = PostFactory( topic=topics[topic_index], author=profiles[post_index % nb_users].user, position=post_index + 1 ) post.text = fake.paragraph(nb_sentences=5, variable_nb_sentences=True) post.text_html = emarkdown(post.text) post.is_useful = int(nb_posts * 0.3) > 0 and post_index % int(nb_posts * 0.3) == 0 post.save() sys.stdout.write(f" Topic {topic_index + 1}/{nb_topics} \tPost {post_index + 1}/{nb_posts} \r") sys.stdout.flush() tps2 = time.time() cli.stdout.write(f"\nFait en {tps2 - tps1} sec")
def item_description(self, item): # TODO: Use cached Markdown when implemented return emarkdown(item.text)
def answer(request): """Adds an answer from an user to a topic.""" try: topic_pk = request.GET['sujet'] except KeyError: raise Http404 # Retrieve current topic. g_topic = get_object_or_404(PrivateTopic, pk=topic_pk) # check if user has right to answer if not g_topic.author == request.user \ and request.user not in list(g_topic.participants.all()): raise PermissionDenied last_post_pk = g_topic.last_message.pk # Retrieve last posts of the current private topic. posts = PrivatePost.objects.filter(privatetopic=g_topic) \ .prefetch_related() \ .order_by("-pubdate")[:settings.ZDS_APP['forum']['posts_per_page']] # User would like preview his post or post a new post on the topic. if request.method == 'POST': data = request.POST newpost = last_post_pk != int(data['last_post']) # Using the « preview button », the « more » button or new post if 'preview' in data or newpost: form = PrivatePostForm(g_topic, request.user, initial={'text': data['text']}) return render_template( 'mp/post/new.html', { 'topic': g_topic, 'last_post_pk': last_post_pk, 'posts': posts, 'newpost': newpost, 'form': form, }) # Saving the message else: form = PrivatePostForm(g_topic, request.user, request.POST) if form.is_valid(): data = form.data post = PrivatePost() post.privatetopic = g_topic post.author = request.user post.text = data['text'] post.text_html = emarkdown(data['text']) post.pubdate = datetime.now() post.position_in_topic = g_topic.get_post_count() + 1 post.save() g_topic.last_message = post g_topic.save() # send email subject = u"{} - MP : {}".format( settings.ZDS_APP['site']['abbr'], g_topic.title) from_email = u"{} <{}>".format( settings.ZDS_APP['site']['litteral_name'], settings.ZDS_APP['site']['email_noreply']) parts = list(g_topic.participants.all()) parts.append(g_topic.author) parts.remove(request.user) for part in parts: profile = part.profile if profile.email_for_answer: pos = post.position_in_topic - 1 last_read = PrivateTopicRead.objects.filter( privatetopic=g_topic, privatepost__position_in_topic=pos, user=part).count() if last_read > 0: message_html = get_template('email/mp/new.html') \ .render( Context({ 'username': part.username, 'url': settings.ZDS_APP['site']['url'] + post.get_absolute_url(), 'author': request.user.username })) message_txt = get_template( 'email/mp/new.txt').render( Context({ 'username': part.username, 'url': settings.ZDS_APP['site']['url'] + post.get_absolute_url(), 'author': request.user.username })) msg = EmailMultiAlternatives( subject, message_txt, from_email, [part.email]) msg.attach_alternative(message_html, "text/html") msg.send() return redirect(post.get_absolute_url()) else: return render_template( 'mp/post/new.html', { 'topic': g_topic, 'last_post_pk': last_post_pk, 'newpost': newpost, 'posts': posts, 'form': form, }) else: text = '' # Using the quote button if 'cite' in request.GET: post_cite_pk = request.GET['cite'] post_cite = get_object_or_404(PrivatePost, pk=post_cite_pk) for line in post_cite.text.splitlines(): text = text + '> ' + line + '\n' text = u'{0}Source:[{1}]({2}{3})'.format( text, post_cite.author.username, settings.ZDS_APP['site']['url'], post_cite.get_absolute_url()) form = PrivatePostForm(g_topic, request.user, initial={'text': text}) return render_template( 'mp/post/new.html', { 'topic': g_topic, 'posts': posts, 'last_post_pk': last_post_pk, 'form': form })
def edit_reaction(request): ''' Edit the given user's reaction ''' try: reaction_pk = request.GET['message'] except KeyError: raise Http404 reaction = get_object_or_404(Reaction, pk=reaction_pk) g_article = None if reaction.position >= 1: g_article = get_object_or_404(Article, pk=reaction.article.pk) # Making sure the user is allowed to do that if reaction.author != request.user: if request.method == 'GET' and request.user.has_perm('article.change_reaction'): messages.add_message( request, messages.WARNING, u'Vous éditez ce message en tant que modérateur (auteur : {}).' u' Soyez encore plus prudent lors de l\'édition de celui-ci !' .format(reaction.author.username)) reaction.alerts.all().delete() if request.method == 'POST': if 'delete-reaction' in request.POST: if reaction.author == request.user or request.user.has_perm('article.change_reaction'): reaction.alerts.all().delete() reaction.is_visible=False if request.user.has_perm('article.change_reaction'): reaction.text_hidden=request.POST['text_hidden'] reaction.editor = request.user if 'show-reaction' in request.POST: if request.user.has_perm('article.change_reaction'): reaction.is_visible=True reaction.text_hidden='' if 'signal-reaction' in request.POST: if reaction.author != request.user : alert = Alert() alert.author = request.user alert.text=request.POST['signal-text'] alert.pubdate = datetime.now() alert.save() reaction.alerts.add(alert) # Using the preview button if 'preview' in request.POST: return render_template('article/edit_reaction.html', { 'reaction': reaction, 'article': g_article, 'text': request.POST['text'], }) if not 'delete-reaction' in request.POST and not 'signal-reaction' in request.POST and not 'show-reaction' in request.POST: # The user just sent data, handle them if request.POST['text'].strip() !='': reaction.text = request.POST['text'] reaction.text_html = emarkdown(request.POST['text']) reaction.update = datetime.now() reaction.editor = request.user reaction.save() return redirect(reaction.get_absolute_url()) else: return render_template('article/edit_reaction.html', { 'reaction': reaction, 'article': g_article, 'text': reaction.text })
def edit_post(request): """Edit the given user's post.""" try: post_pk = request.GET["message"] except KeyError: raise Http404 post = get_object_or_404(Post, pk=post_pk) if not post.topic.forum.can_read(request.user): raise PermissionDenied g_topic = None if post.position <= 1: g_topic = get_object_or_404(Topic, pk=post.topic.pk) # Making sure the user is allowed to do that. Author of the post must to be # the user logged. if post.author != request.user \ and not request.user.has_perm("forum.change_post") and "signal_message" \ not in request.POST: raise PermissionDenied if post.author != request.user and request.method == "GET" \ and request.user.has_perm("forum.change_post"): messages.warning(request, u'Vous \xe9ditez ce message en tant que ' u'mod\xe9rateur (auteur : {}). Soyez encore plus ' u'prudent lors de l\'\xe9dition de celui-ci !' .format(post.author.username)) if request.method == "POST": if "delete_message" in request.POST: if post.author == request.user \ or request.user.has_perm("forum.change_post"): post.alerts.all().delete() post.is_visible = False if request.user.has_perm("forum.change_post"): post.text_hidden = request.POST["text_hidden"] post.editor = request.user messages.success(request, u"Le message est désormais masqué") if "show_message" in request.POST: if request.user.has_perm("forum.change_post"): post.is_visible = True post.text_hidden = "" if "signal_message" in request.POST: alert = Alert() alert.author = request.user alert.comment = post alert.scope = Alert.FORUM alert.text = request.POST['signal_text'] alert.pubdate = datetime.now() alert.save() messages.success(request, u'Une alerte a été envoyée ' u'à l\'équipe concernant ' u'ce message') # Using the preview button if "preview" in request.POST: if g_topic: form = TopicForm(initial={"title": request.POST["title"], "subtitle": request.POST["subtitle"], "text": request.POST["text"]}) else: form = PostForm(post.topic, request.user, initial={"text": request.POST["text"]}) form.helper.form_action = reverse("zds.forum.views.edit_post") \ + "?message=" + str(post_pk) return render_template("forum/post/edit.html", { "post": post, "topic": post.topic, "text": request.POST["text"], "form": form, }) if "delete_message" not in request.POST and "signal_message" \ not in request.POST and "show_message" not in request.POST: # The user just sent data, handle them if request.POST["text"].strip() != "": post.text = request.POST["text"] post.text_html = emarkdown(request.POST["text"]) post.update = datetime.now() post.editor = request.user # Modifying the thread info if g_topic: (tags, title) = get_tag_by_title(request.POST["title"]) g_topic.title = title g_topic.subtitle = request.POST["subtitle"] g_topic.save() g_topic.tags.clear() # add tags g_topic.add_tags(tags) post.save() return redirect(post.get_absolute_url()) else: if g_topic: prefix = u"" for tag in g_topic.tags.all(): prefix += u"[{0}]".format(tag.title) form = TopicForm( initial={ "title": u"{0} {1}".format( prefix, g_topic.title).strip(), "subtitle": g_topic.subtitle, "text": post.text}) else: form = PostForm(post.topic, request.user, initial={"text": post.text}) form.helper.form_action = reverse("zds.forum.views.edit_post") \ + "?message=" + str(post_pk) return render_template("forum/post/edit.html", { "post": post, "topic": post.topic, "text": post.text, "form": form, })
def new(request): """Creates a new topic in a forum.""" try: forum_pk = request.GET["forum"] except KeyError: raise Http404 forum = get_object_or_404(Forum, pk=forum_pk) if not forum.can_read(request.user): raise PermissionDenied if request.method == "POST": # If the client is using the "preview" button if "preview" in request.POST: form = TopicForm(initial={"title": request.POST["title"], "subtitle": request.POST["subtitle"], "text": request.POST["text"]}) return render_template("forum/topic/new.html", {"forum": forum, "form": form, "text": request.POST["text"]}) form = TopicForm(request.POST) data = form.data if form.is_valid(): # Treat title (tags, title) = get_tag_by_title(data["title"]) # Creating the thread n_topic = Topic() n_topic.forum = forum n_topic.title = title n_topic.subtitle = data["subtitle"] n_topic.pubdate = datetime.now() n_topic.author = request.user n_topic.save() # add tags n_topic.add_tags(tags) n_topic.save() # Adding the first message post = Post() post.topic = n_topic post.author = request.user post.text = data["text"] post.text_html = emarkdown(request.POST["text"]) post.pubdate = datetime.now() post.position = 1 post.ip_address = get_client_ip(request) post.save() n_topic.last_message = post n_topic.save() # Follow the topic follow(n_topic) return redirect(n_topic.get_absolute_url()) else: form = TopicForm() return render_template("forum/topic/new.html", {"forum": forum, "form": form})
def answer(request): """Adds an answer from a user to a topic.""" try: topic_pk = request.GET["sujet"] except: # problem in variable format raise Http404 # Retrieve current topic. g_topic = get_object_or_404(Topic, pk=topic_pk) if not g_topic.forum.can_read(request.user): raise PermissionDenied # Making sure posting is allowed if g_topic.is_locked: raise PermissionDenied # Check that the user isn't spamming if g_topic.antispam(request.user): raise PermissionDenied last_post_pk = g_topic.last_message.pk # Retrieve last posts of the current topic. posts = Post.objects.filter(topic=g_topic) \ .prefetch_related() \ .order_by("-pubdate")[:settings.POSTS_PER_PAGE] # User would like preview his post or post a new post on the topic. if request.method == "POST": data = request.POST newpost = last_post_pk != int(data["last_post"]) # Using the « preview button », the « more » button or new post if "preview" in data or newpost: form = PostForm(g_topic, request.user, initial={"text": data["text"]}) form.helper.form_action = reverse("zds.forum.views.answer") \ + "?sujet=" + str(g_topic.pk) return render_template("forum/post/new.html", { "text": data["text"], "topic": g_topic, "posts": posts, "last_post_pk": last_post_pk, "newpost": newpost, "form": form, }) else: # Saving the message form = PostForm(g_topic, request.user, request.POST) if form.is_valid(): data = form.data post = Post() post.topic = g_topic post.author = request.user post.text = data["text"] post.text_html = emarkdown(data["text"]) post.pubdate = datetime.now() post.position = g_topic.get_post_count() + 1 post.ip_address = get_client_ip(request) post.save() g_topic.last_message = post g_topic.save() #Send mail subject = "ZDS - Notification : " + g_topic.title from_email = "Zeste de Savoir <{0}>".format(settings.MAIL_NOREPLY) followers = g_topic.get_followers_by_email() for follower in followers: receiver = follower.user if receiver == request.user: continue pos = post.position - 1 last_read = TopicRead.objects.filter( topic=g_topic, post__position=pos, user=receiver).count() if last_read > 0: message_html = get_template('email/notification/new.html') \ .render( Context({ 'username': receiver.username, 'title':g_topic.title, 'url': settings.SITE_URL + post.get_absolute_url(), 'author': request.user.username }) ) message_txt = get_template('email/notification/new.txt').render( Context({ 'username': receiver.username, 'title':g_topic.title, 'url': settings.SITE_URL + post.get_absolute_url(), 'author': request.user.username }) ) msg = EmailMultiAlternatives( subject, message_txt, from_email, [ receiver.email]) msg.attach_alternative(message_html, "text/html") msg.send() # Follow topic on answering if not g_topic.is_followed(user=request.user): follow(g_topic) return redirect(post.get_absolute_url()) else: return render_template("forum/post/new.html", { "text": data["text"], "topic": g_topic, "posts": posts, "last_post_pk": last_post_pk, "newpost": newpost, "form": form, }) else: # Actions from the editor render to new.html. text = "" # Using the quote button if "cite" in request.GET: post_cite_pk = request.GET["cite"] post_cite = Post.objects.get(pk=post_cite_pk) if not post_cite.is_visible: raise PermissionDenied for line in post_cite.text.splitlines(): text = text + "> " + line + "\n" text = u"{0}Source:[{1}]({2}{3})".format( text, post_cite.author.username, settings.SITE_URL, post_cite.get_absolute_url()) form = PostForm(g_topic, request.user, initial={"text": text}) form.helper.form_action = reverse("zds.forum.views.answer") \ + "?sujet=" + str(g_topic.pk) return render_template("forum/post/new.html", { "topic": g_topic, "posts": posts, "last_post_pk": last_post_pk, "form": form, })
def reindex_content(published_content): """Index the new published version. .. attention:: Note that lots of IO, memory and CPU will be used when you use this function. Only loop on it if you know what you are doing ! This function looks for the archive generated in any publication and containing the content in a version that correspond to the public version, and then use it to create ``SearchIndex*`` objects by reading the archive. IO complexity is ``2 + 2 * number of containers + number of extracts`` (through a ZIP archive). Database query complexity is * on deletion : ``1 + number of containers + number of extracts`` ; * on addition : ``1 + number of containers + number of extracts``. :param published_content: Database representation of the public version of the content :type published_content: PublishedContent """ # We just delete all index that correspond to the content SearchIndexContent.objects.filter( publishable_content__pk=published_content.content_pk).delete() # Load the manifest: if not published_content.have_zip(): raise Exception( 'Unable to index content due to the absence of ZIP file') zip_path = os.path.join(published_content.get_extra_contents_directory(), published_content.content_public_slug + '.zip') archive = zipfile.ZipFile(zip_path) try: manifest = get_file_content_in_zip(archive, 'manifest.json') except KeyError: raise Exception( 'Unable to index content due to the absence of manifest in ZIP file' ) json_ = json_reader.loads(manifest) try: versioned = get_content_from_json(json_, None, '') except BadManifestError as e: raise Exception(e.message) except Exception: raise Exception( 'Unable to index content due to an error while opening manifest') published_content.content.insert_data_in_versioned(versioned) # Index the content: search_index_content = SearchIndexContent() search_index_content.publishable_content = published_content.content search_index_content.pubdate = published_content.publication_date or datetime.now( ) search_index_content.update_date = published_content.content.update_date or datetime.now( ) if published_content.content.licence: search_index_content.licence = published_content.content.licence.title else: search_index_content.licence = '' if published_content.content.image: search_index_content.url_image = published_content.content.image.get_absolute_url( ) else: search_index_content.url_image = '' search_index_content.title = versioned.title search_index_content.description = versioned.description search_index_content.save() # Subcategory for subcategory in published_content.content.subcategory.all(): search_index_tag = SearchIndexTag() search_index_tag.title = subcategory.title search_index_tag.save() search_index_content.tags.add(search_index_tag) # Authors for author in published_content.content.authors.all(): search_index_authors = SearchIndexAuthors() search_index_authors.username = author.username search_index_authors.save() search_index_content.authors.add(search_index_authors) search_index_content.url_to_redirect = published_content.get_absolute_url_online( ) # Save introduction and conclusion: all_html = u'' if versioned.introduction: try: introduction_html = emarkdown( get_file_content_in_zip(archive, versioned.introduction)) all_html = introduction_html search_index_content.introduction = filter_text(introduction_html) except KeyError: pass if versioned.conclusion: try: conclusion_html = emarkdown( get_file_content_in_zip(archive, versioned.conclusion)) all_html = u'{}{}'.format(all_html, conclusion_html) search_index_content.conclusion = filter_text(conclusion_html) except KeyError: pass if all_html != u'': search_index_content.keywords = filter_keyword(all_html) search_index_content.type = published_content.content_type.lower() search_index_content.save() # Also index children index_content(versioned, search_index_content, archive) # no need to index the next time published_content.content.must_reindex = False published_content.content.save()
def edit_reaction(request): """Edit the given user's reaction.""" try: reaction_pk = request.GET['message'] except KeyError: raise Http404 reaction = get_object_or_404(Reaction, pk=reaction_pk) g_article = None if reaction.position >= 1: g_article = get_object_or_404(Article, pk=reaction.article.pk) # Making sure the user is allowed to do that. Author of the reaction # must to be the user logged. if reaction.author != request.user \ and not request.user.has_perm('article.change_reaction') \ and 'signal_message' not in request.POST: raise PermissionDenied if reaction.author != request.user \ and request.method == 'GET' \ and request.user.has_perm('article.change_reaction'): messages.add_message( request, messages.WARNING, u'Vous éditez ce message en tant que modérateur (auteur : {}).' u' Soyez encore plus prudent lors de l\'édition de celui-ci !'. format(reaction.author.username)) reaction.alerts.all().delete() if request.method == 'POST': if 'delete_message' in request.POST: if reaction.author == request.user \ or request.user.has_perm('article.change_reaction'): reaction.alerts.all().delete() reaction.is_visible = False if request.user.has_perm('article.change_reaction'): reaction.text_hidden = request.POST['text_hidden'] reaction.editor = request.user if 'show_message' in request.POST: if request.user.has_perm('article.change_reaction'): reaction.is_visible = True reaction.text_hidden = '' if 'signal_message' in request.POST: alert = Alert() alert.author = request.user alert.comment = reaction alert.scope = Alert.ARTICLE alert.text = request.POST['signal_text'] alert.pubdate = datetime.now() alert.save() # Using the preview button if 'preview' in request.POST: form = ReactionForm(g_article, request.user, initial={'text': request.POST['text']}) form.helper.form_action = reverse( 'zds.article.views.edit_reaction') + \ '?message=' + \ str(reaction_pk) return render_template('article/reaction/edit.html', { 'reaction': reaction, 'article': g_article, 'form': form }) if 'delete_message' not in request.POST \ and 'signal_message' not in request.POST \ and 'show_message' not in request.POST: # The user just sent data, handle them if request.POST['text'].strip() != '': reaction.text = request.POST['text'] reaction.text_html = emarkdown(request.POST['text']) reaction.update = datetime.now() reaction.editor = request.user reaction.save() return redirect(reaction.get_absolute_url()) else: form = ReactionForm(g_article, request.user, initial={'text': reaction.text}) form.helper.form_action = reverse( 'zds.article.views.edit_reaction') + '?message=' + str(reaction_pk) return render_template('article/reaction/edit.html', { 'reaction': reaction, 'article': g_article, 'form': form })
def answer(request): """Adds an answer from a user to an article.""" try: article_pk = request.GET['article'] except KeyError: raise Http404 # Retrieve current article. article = get_object_or_404(Article, pk=article_pk) # Making sure reactioning is allowed if article.is_locked: raise PermissionDenied # Check that the user isn't spamming if article.antispam(request.user): raise PermissionDenied # Retrieve 3 last reactions of the currenta article. reactions = Reaction.objects\ .filter(article=article)\ .order_by('-pubdate')[:3] # If there is a last reaction for the article, we save his pk. # Otherwise, we save 0. if article.last_reaction: last_reaction_pk = article.last_reaction.pk else: last_reaction_pk = 0 # User would like preview his post or post a new reaction on the article. if request.method == 'POST': data = request.POST newreaction = last_reaction_pk != int(data['last_reaction']) # Using the « preview button », the « more » button or new reaction if 'preview' in data or newreaction: form = ReactionForm(article, request.user, initial={'text': data['text']}) return render_template( 'article/reaction/new.html', { 'article': article, 'last_reaction_pk': last_reaction_pk, 'newreaction': newreaction, 'form': form }) # Saving the message else: form = ReactionForm(article, request.user, request.POST) if form.is_valid(): data = form.data reaction = Reaction() reaction.article = article reaction.author = request.user reaction.text = data['text'] reaction.text_html = emarkdown(data['text']) reaction.pubdate = datetime.now() reaction.position = article.get_reaction_count() + 1 reaction.ip_address = get_client_ip(request) reaction.save() article.last_reaction = reaction article.save() return redirect(reaction.get_absolute_url()) else: return render_template( 'article/reaction/new.html', { 'article': article, 'last_reaction_pk': last_reaction_pk, 'newreaction': newreaction, 'form': form }) # Actions from the editor render to new.html. else: text = '' # Using the quote button if 'cite' in request.GET: reaction_cite_pk = request.GET['cite'] reaction_cite = Reaction.objects.get(pk=reaction_cite_pk) if not reaction_cite.is_visible: raise PermissionDenied for line in reaction_cite.text.splitlines(): text = text + '> ' + line + '\n' text = u'{0}Source:[{1}]({2}{3})'.format( text, reaction_cite.author.username, settings.SITE_URL, reaction_cite.get_absolute_url()) form = ReactionForm(article, request.user, initial={'text': text}) return render_template( 'article/reaction/new.html', { 'article': article, 'reactions': reactions, 'last_reaction_pk': last_reaction_pk, 'form': form })
def send_mp( author, users, title, subtitle, text, send_by_mail=True, leave=True, direct=False): """Send MP at members.""" # Creating the thread n_topic = PrivateTopic() n_topic.title = title[:80] n_topic.subtitle = subtitle n_topic.pubdate = datetime.now() n_topic.author = author n_topic.save() # Add all participants on the MP. for part in users: n_topic.participants.add(part) # Addi the first message post = PrivatePost() post.privatetopic = n_topic post.author = author post.text = text post.text_html = emarkdown(text) post.pubdate = datetime.now() post.position_in_topic = 1 post.save() n_topic.last_message = post n_topic.save() # send email if send_by_mail: if direct: subject = "ZDS : " + n_topic.title from_email = "Zeste de Savoir <{0}>".format(settings.MAIL_NOREPLY) for part in users: message_html = get_template('email/mp/direct.html').render( Context({ 'msg': emarkdown(text) }) ) message_txt = get_template('email/mp/direct.txt').render( Context({ 'msg': text }) ) msg = EmailMultiAlternatives( subject, message_txt, from_email, [ part.email]) msg.attach_alternative(message_html, "text/html") try: msg.send() except: msg = None else: subject = "ZDS - MP: " + n_topic.title from_email = "Zeste de Savoir <{0}>".format(settings.MAIL_NOREPLY) for part in users: message_html = get_template('email/mp/new.html').render( Context({ 'username': part.username, 'url': settings.SITE_URL + n_topic.get_absolute_url(), 'author': author.username }) ) message_txt = get_template('email/mp/new.txt').render( Context({ 'username': part.username, 'url': settings.SITE_URL + n_topic.get_absolute_url(), 'author': author.username }) ) msg = EmailMultiAlternatives( subject, message_txt, from_email, [ part.email]) msg.attach_alternative(message_html, "text/html") try: msg.send() except: msg = None if leave: move = n_topic.participants.first() n_topic.author = move n_topic.participants.remove(move) n_topic.save() return n_topic
def send_message_mp(author, n_topic, text, send_by_mail=True, direct=False, hat=None, no_notification_for=None): """ Send a post in an MP. :param author: sender of the private message :param n_topic: topic in which it will be sent :param text: content of the message :param send_by_mail: if True, also notify by email :param direct: send a mail directly without private message (ex : banned members who won't connect again) :param hat: hat attached to the message :param no_notification_for: list of participants who won't be notified of the message """ # Getting the position of the post if n_topic.last_message is None: pos = 1 else: pos = n_topic.last_message.position_in_topic + 1 # Add the first message post = PrivatePost() post.privatetopic = n_topic post.author = author post.text = text post.text_html = emarkdown(text) post.pubdate = datetime.now() post.position_in_topic = pos post.hat = hat post.save() n_topic.last_message = post n_topic.save() if not direct: signals.message_added.send(sender=post.__class__, post=post, by_email=send_by_mail, no_notification_for=no_notification_for) if send_by_mail and direct: subject = "{} : {}".format(settings.ZDS_APP["site"]["literal_name"], n_topic.title) from_email = "{} <{}>".format( settings.ZDS_APP["site"]["literal_name"], settings.ZDS_APP["site"]["email_noreply"]) for recipient in n_topic.participants.values_list("email", flat=True): message_html = render_to_string("email/direct.html", {"msg": emarkdown(text)}) message_txt = render_to_string("email/direct.txt", {"msg": text}) msg = EmailMultiAlternatives(subject, message_txt, from_email, [recipient]) msg.attach_alternative(message_html, "text/html") try: msg.send() except Exception as e: logger.exception("Message was not sent to %s due to %s", recipient, e) if no_notification_for: if not isinstance(no_notification_for, list): no_notification_for = [no_notification_for] for not_notified_user in no_notification_for: mark_read(n_topic, not_notified_user) # There's no need to inform of the new participant # because participants are already notified through the `message_added` signal. # If we tried to add the bot, that's fine (a better solution would be welcome though) with suppress(NotReachableError): n_topic.add_participant(author, silent=True) n_topic.save() return n_topic
def edit_post(request): """Edit the given user's post.""" try: post_pk = request.GET['message'] except KeyError: raise Http404 post = get_object_or_404(PrivatePost, pk=post_pk) # Only edit last private post tp = get_object_or_404(PrivateTopic, pk=post.privatetopic.pk) last = get_object_or_404(PrivatePost, pk=tp.last_message.pk) if not last.pk == post.pk: raise PermissionDenied g_topic = None if post.position_in_topic >= 1: g_topic = get_object_or_404(PrivateTopic, pk=post.privatetopic.pk) # Making sure the user is allowed to do that. Author of the post # must to be the user logged. if post.author != request.user: raise PermissionDenied if request.method == 'POST': if 'text' not in request.POST: # if preview mode return on if 'preview' in request.POST: return redirect( reverse('zds.mp.views.edit_post') + '?message=' + str(post_pk)) # disallow send mp else: raise PermissionDenied # Using the preview button if 'preview' in request.POST: form = PrivatePostForm(g_topic, request.user, initial={'text': request.POST['text']}) form.helper.form_action = reverse( 'zds.mp.views.edit_post') + '?message=' + str(post_pk) return render_template('mp/post/edit.html', { 'post': post, 'topic': g_topic, 'form': form, }) # The user just sent data, handle them post.text = request.POST['text'] post.text_html = emarkdown(request.POST['text']) post.update = datetime.now() post.save() return redirect(post.get_absolute_url()) else: form = PrivatePostForm(g_topic, request.user, initial={'text': post.text}) form.helper.form_action = reverse( 'zds.mp.views.edit_post') + '?message=' + str(post_pk) return render_template('mp/post/edit.html', { 'post': post, 'topic': g_topic, 'text': post.text, 'form': form, })
def publish_container(db_object, base_dir, container, template='tutorialv2/export/chapter.html', file_ext='html', image_callback=None, **ctx): """ 'Publish' a given container, in a recursive way :param image_callback: callback used to change images tags on the created html :type image_callback: callable :param db_object: database representation of the content :type db_object: PublishableContent :param base_dir: directory of the top container :type base_dir: str :param template: the django template we will use to produce chapter export to html. :param container: a given container :type container: Container :param file_ext: output file extension :raise FailureDuringPublication: if anything goes wrong """ from zds.tutorialv2.models.versioned import Container from zds.tutorialv2.publication_utils import FailureDuringPublication path_to_title_dict = collections.OrderedDict() ctx['relative'] = ctx.get('relative', '.') if not isinstance(container, Container): raise FailureDuringPublication(_(u"Le conteneur n'en est pas un !")) # jsFiddle support is_js = '' if db_object.js_support: is_js = 'js' current_dir = path.dirname( path.join(base_dir, container.get_prod_path(relative=True))) if not path.isdir(current_dir): makedirs(current_dir) if container.has_extracts( ): # the container can be rendered in one template img_relative_path = '..' if ctx[ 'relative'] == '.' else '../' + ctx['relative'] wrapped_image_callback = image_callback( img_relative_path) if image_callback else image_callback args = {'container': container, 'is_js': is_js} args.update(ctx) parsed = render_to_string(template, args) write_chapter_file(base_dir, container, Path(container.get_prod_path(True, file_ext)), parsed, path_to_title_dict, wrapped_image_callback) for extract in container.children: extract.text = None container.introduction = None container.conclusion = None else: # separate render of introduction and conclusion wrapped_image_callback = image_callback( ctx['relative']) if image_callback else image_callback # create subdirectory if not path.isdir(current_dir): makedirs(current_dir) ctx['relative'] = '../' + ctx['relative'] if container.introduction and container.get_introduction(): part_path = Path(container.get_prod_path(relative=True), 'introduction.' + file_ext) parsed = emarkdown(container.get_introduction(), db_object.js_support) container.introduction = str(part_path) write_chapter_file(base_dir, container, part_path, parsed, path_to_title_dict, wrapped_image_callback) children = copy.copy(container.children) container.children = [] container.children_dict = {} for child in filter(lambda c: c.ready_to_publish, children): altered_version = copy.copy(child) container.children.append(altered_version) container.children_dict[altered_version.slug] = altered_version result = publish_container(db_object, base_dir, altered_version, file_ext=file_ext, image_callback=image_callback, template=template, **ctx) path_to_title_dict.update(result) if container.conclusion and container.get_conclusion(): part_path = Path(container.get_prod_path(relative=True), 'conclusion.' + file_ext) parsed = emarkdown(container.get_conclusion(), db_object.js_support) container.conclusion = str(part_path) write_chapter_file(base_dir, container, part_path, parsed, path_to_title_dict, wrapped_image_callback) return path_to_title_dict
def new(request): """Creates a new topic in a forum.""" try: forum_pk = request.GET["forum"] except: # problem in variable format raise Http404 forum = get_object_or_404(Forum, pk=forum_pk) if not forum.can_read(request.user): raise PermissionDenied if request.method == "POST": # If the client is using the "preview" button if "preview" in request.POST: form = TopicForm(initial={"title": request.POST["title"], "subtitle": request.POST["subtitle"], "text": request.POST["text"]}) return render_template("forum/topic/new.html", {"forum": forum, "form": form, "text": request.POST["text"]}) form = TopicForm(request.POST) data = form.data if form.is_valid(): # Treat title (tags, title) = get_tag_by_title(data["title"]) # Creating the thread n_topic = Topic() n_topic.forum = forum n_topic.title = title n_topic.subtitle = data["subtitle"] n_topic.pubdate = datetime.now() n_topic.author = request.user n_topic.save() # add tags n_topic.add_tags(tags) n_topic.save() # Adding the first message post = Post() post.topic = n_topic post.author = request.user post.text = data["text"] post.text_html = emarkdown(request.POST["text"]) post.pubdate = datetime.now() post.position = 1 post.ip_address = get_client_ip(request) post.save() n_topic.last_message = post n_topic.save() # Follow the topic follow(n_topic) return redirect(n_topic.get_absolute_url()) else: form = TopicForm() return render_template("forum/topic/new.html", {"forum": forum, "form": form})
def edit_reaction(request): """Edit the given user's reaction.""" try: reaction_pk = request.GET['message'] except KeyError: raise Http404 reaction = get_object_or_404(Reaction, pk=reaction_pk) g_article = None if reaction.position >= 1: g_article = get_object_or_404(Article, pk=reaction.article.pk) # Making sure the user is allowed to do that. Author of the reaction # must to be the user logged. if reaction.author != request.user \ and not request.user.has_perm('article.change_reaction') \ and 'signal_message' not in request.POST: raise PermissionDenied if reaction.author != request.user \ and request.method == 'GET' \ and request.user.has_perm('article.change_reaction'): messages.add_message( request, messages.WARNING, u'Vous éditez ce message en tant que modérateur (auteur : {}).' u' Soyez encore plus prudent lors de l\'édition de celui-ci !' .format(reaction.author.username)) reaction.alerts.all().delete() if request.method == 'POST': if 'delete_message' in request.POST: if reaction.author == request.user \ or request.user.has_perm('article.change_reaction'): reaction.alerts.all().delete() reaction.is_visible = False if request.user.has_perm('article.change_reaction'): reaction.text_hidden = request.POST['text_hidden'] reaction.editor = request.user if 'show_message' in request.POST: if request.user.has_perm('article.change_reaction'): reaction.is_visible = True reaction.text_hidden = '' if 'signal_message' in request.POST: alert = Alert() alert.author = request.user alert.comment = reaction alert.scope = Alert.ARTICLE alert.text = request.POST['signal_text'] alert.pubdate = datetime.now() alert.save() # Using the preview button if 'preview' in request.POST: form = ReactionForm(g_article, request.user, initial={ 'text': request.POST['text'] }) form.helper.form_action = reverse( 'zds.article.views.edit_reaction') + \ '?message=' + \ str(reaction_pk) return render_template('article/reaction/edit.html', { 'reaction': reaction, 'article': g_article, 'form': form }) if 'delete_message' not in request.POST \ and 'signal_message' not in request.POST \ and 'show_message' not in request.POST: # The user just sent data, handle them if request.POST['text'].strip() != '': reaction.text = request.POST['text'] reaction.text_html = emarkdown(request.POST['text']) reaction.update = datetime.now() reaction.editor = request.user reaction.save() return redirect(reaction.get_absolute_url()) else: form = ReactionForm(g_article, request.user, initial={ 'text': reaction.text }) form.helper.form_action = reverse( 'zds.article.views.edit_reaction') + '?message=' + str(reaction_pk) return render_template('article/reaction/edit.html', { 'reaction': reaction, 'article': g_article, 'form': form })
def edit_post(request): """Edit the given user's post.""" try: post_pk = request.GET["message"] except: # problem in variable format raise Http404 post = get_object_or_404(Post, pk=post_pk) if not post.topic.forum.can_read(request.user): raise PermissionDenied g_topic = None if post.position <= 1: g_topic = get_object_or_404(Topic, pk=post.topic.pk) # Making sure the user is allowed to do that. Author of the post must to be # the user logged. if post.author != request.user \ and not request.user.has_perm("forum.change_post") and "signal_message" \ not in request.POST: raise PermissionDenied if post.author != request.user and request.method == "GET" \ and request.user.has_perm("forum.change_post"): messages.warning(request, u'Vous \xe9ditez ce message en tant que ' u'mod\xe9rateur (auteur : {}). Soyez encore plus ' u'prudent lors de l\'\xe9dition de celui-ci !' .format(post.author.username)) if request.method == "POST": if "delete_message" in request.POST: if post.author == request.user \ or request.user.has_perm("forum.change_post"): post.alerts.all().delete() post.is_visible = False if request.user.has_perm("forum.change_post"): post.text_hidden = request.POST["text_hidden"] post.editor = request.user messages.success(request, u"Le message est désormais masqué") if "show_message" in request.POST: if request.user.has_perm("forum.change_post"): post.is_visible = True post.text_hidden = "" if "signal_message" in request.POST: alert = Alert() alert.author = request.user alert.comment = post alert.scope = Alert.FORUM alert.text = request.POST['signal_text'] alert.pubdate = datetime.now() alert.save() messages.success(request, u'Une alerte a été envoyée ' u'à l\'équipe concernant ' u'ce message') # Using the preview button if "preview" in request.POST: if g_topic: form = TopicForm(initial={"title": request.POST["title"], "subtitle": request.POST["subtitle"], "text": request.POST["text"]}) else: form = PostForm(post.topic, request.user, initial={"text": request.POST["text"]}) form.helper.form_action = reverse("zds.forum.views.edit_post") \ + "?message=" + str(post_pk) return render_template("forum/post/edit.html", { "post": post, "topic": post.topic, "text": request.POST["text"], "form": form, }) if "delete_message" not in request.POST and "signal_message" \ not in request.POST and "show_message" not in request.POST: # The user just sent data, handle them if request.POST["text"].strip() != "": post.text = request.POST["text"] post.text_html = emarkdown(request.POST["text"]) post.update = datetime.now() post.editor = request.user # Modifying the thread info if g_topic: (tags, title) = get_tag_by_title(request.POST["title"]) g_topic.title = title g_topic.subtitle = request.POST["subtitle"] g_topic.save() g_topic.tags.clear() # add tags g_topic.add_tags(tags) post.save() return redirect(post.get_absolute_url()) else: if g_topic: prefix = u"" for tag in g_topic.tags.all(): prefix += u"[{0}]".format(tag.title) form = TopicForm( initial={ "title": u"{0} {1}".format( prefix, g_topic.title).strip(), "subtitle": g_topic.subtitle, "text": post.text}) else: form = PostForm(post.topic, request.user, initial={"text": post.text}) form.helper.form_action = reverse("zds.forum.views.edit_post") \ + "?message=" + str(post_pk) return render_template("forum/post/edit.html", { "post": post, "topic": post.topic, "text": post.text, "form": form, })
def answer(request): """Adds an answer from a user to an article.""" try: article_pk = request.GET['article'] except KeyError: raise Http404 # Retrieve current article. article = get_object_or_404(Article, pk=article_pk) # Making sure reactioning is allowed if article.is_locked: raise PermissionDenied # Check that the user isn't spamming if article.antispam(request.user): raise PermissionDenied # Retrieve 3 last reactions of the currenta article. reactions = Reaction.objects\ .filter(article=article)\ .order_by('-pubdate')[:3] # If there is a last reaction for the article, we save his pk. # Otherwise, we save 0. if article.last_reaction: last_reaction_pk = article.last_reaction.pk else: last_reaction_pk = 0 # User would like preview his post or post a new reaction on the article. if request.method == 'POST': data = request.POST newreaction = last_reaction_pk != int(data['last_reaction']) # Using the « preview button », the « more » button or new reaction if 'preview' in data or newreaction: form = ReactionForm(article, request.user, initial={ 'text': data['text'] }) return render_template('article/reaction/new.html', { 'article': article, 'last_reaction_pk': last_reaction_pk, 'newreaction': newreaction, 'form': form }) # Saving the message else: form = ReactionForm(article, request.user, request.POST) if form.is_valid(): data = form.data reaction = Reaction() reaction.article = article reaction.author = request.user reaction.text = data['text'] reaction.text_html = emarkdown(data['text']) reaction.pubdate = datetime.now() reaction.position = article.get_reaction_count() + 1 reaction.ip_address = get_client_ip(request) reaction.save() article.last_reaction = reaction article.save() return redirect(reaction.get_absolute_url()) else: return render_template('article/reaction/new.html', { 'article': article, 'last_reaction_pk': last_reaction_pk, 'newreaction': newreaction, 'form': form }) # Actions from the editor render to new.html. else: text = '' # Using the quote button if 'cite' in request.GET: reaction_cite_pk = request.GET['cite'] reaction_cite = Reaction.objects.get(pk=reaction_cite_pk) if not reaction_cite.is_visible: raise PermissionDenied for line in reaction_cite.text.splitlines(): text = text + '> ' + line + '\n' text = u'{0}Source:[{1}]({2}{3})'.format( text, reaction_cite.author.username, settings.SITE_URL, reaction_cite.get_absolute_url()) form = ReactionForm(article, request.user, initial={ 'text': text }) return render_template('article/reaction/new.html', { 'article': article, 'reactions': reactions, 'last_reaction_pk': last_reaction_pk, 'form': form })
def answer(request): """Adds an answer from a user to a topic.""" try: topic_pk = request.GET["sujet"] except KeyError: raise Http404 # Retrieve current topic. g_topic = get_object_or_404(Topic, pk=topic_pk) if not g_topic.forum.can_read(request.user): raise PermissionDenied # Making sure posting is allowed if g_topic.is_locked: raise PermissionDenied # Check that the user isn't spamming if g_topic.antispam(request.user): raise PermissionDenied last_post_pk = g_topic.last_message.pk # Retrieve 10 last posts of the current topic. posts = \ Post.objects.filter(topic=g_topic) \ .prefetch_related() \ .order_by("-pubdate" )[:10] # User would like preview his post or post a new post on the topic. if request.method == "POST": data = request.POST newpost = last_post_pk != int(data["last_post"]) # Using the « preview button », the « more » button or new post if "preview" in data or newpost: form = PostForm(g_topic, request.user, initial={"text": data["text" ]}) form.helper.form_action = reverse("zds.forum.views.answer") \ + "?sujet=" + str(g_topic.pk) return render_template("forum/post/new.html", { "text": data["text"], "topic": g_topic, "posts": posts, "last_post_pk": last_post_pk, "newpost": newpost, "form": form, }) else: # Saving the message form = PostForm(g_topic, request.user, request.POST) if form.is_valid(): data = form.data post = Post() post.topic = g_topic post.author = request.user post.text = data["text"] post.text_html = emarkdown(data["text"]) post.pubdate = datetime.now() post.position = g_topic.get_post_count() + 1 post.ip_address = get_client_ip(request) post.save() g_topic.last_message = post g_topic.save() #Send mail subject = "ZDS - Notification : " + g_topic.title from_email = "Zeste de Savoir <{0}>".format(settings.MAIL_NOREPLY) followers = g_topic.get_followers_by_email() for follower in followers: receiver = follower.user if receiver == request.user: continue pos = post.position - 1 last_read = TopicRead.objects.filter( topic=g_topic, post__position=pos, user=receiver).count() if last_read > 0: message_html = get_template('email/notification/new.html') \ .render( Context({ 'username': receiver.username, 'title':g_topic.title, 'url': settings.SITE_URL + post.get_absolute_url(), 'author': request.user.username }) ) message_txt = get_template('email/notification/new.txt').render( Context({ 'username': receiver.username, 'title':g_topic.title, 'url': settings.SITE_URL + post.get_absolute_url(), 'author': request.user.username }) ) msg = EmailMultiAlternatives( subject, message_txt, from_email, [ receiver.email]) msg.attach_alternative(message_html, "text/html") msg.send() # Follow topic on answering if not g_topic.is_followed(user=request.user): follow(g_topic) return redirect(post.get_absolute_url()) else: return render_template("forum/post/new.html", { "text": data["text"], "topic": g_topic, "posts": posts, "last_post_pk": last_post_pk, "newpost": newpost, "form": form, }) else: # Actions from the editor render to new.html. text = "" # Using the quote button if "cite" in request.GET: post_cite_pk = request.GET["cite"] post_cite = Post.objects.get(pk=post_cite_pk) if not post_cite.is_visible: raise PermissionDenied for line in post_cite.text.splitlines(): text = text + "> " + line + "\n" text = u"{0}Source:[{1}]({2}{3})".format( text, post_cite.author.username, settings.SITE_URL, post_cite.get_absolute_url()) form = PostForm(g_topic, request.user, initial={"text": text}) form.helper.form_action = reverse("zds.forum.views.answer") \ + "?sujet=" + str(g_topic.pk) return render_template("forum/post/new.html", { "topic": g_topic, "posts": posts, "last_post_pk": last_post_pk, "form": form, })
def answer(request): """Adds an answer from an user to a topic.""" try: topic_pk = request.GET['sujet'] except KeyError: raise Http404 # Retrieve current topic. g_topic = get_object_or_404(PrivateTopic, pk=topic_pk) # Retrieve 3 last posts of the currenta topic. posts = PrivatePost.objects\ .filter(privatetopic=g_topic)\ .order_by('-pubdate')[:3] last_post_pk = g_topic.last_message.pk # User would like preview his post or post a new post on the topic. if request.method == 'POST': data = request.POST newpost = last_post_pk != int(data['last_post']) # Using the « preview button », the « more » button or new post if 'preview' in data or newpost: form = PrivatePostForm(g_topic, request.user, initial={ 'text': data['text'] }) return render_template('mp/post/new.html', { 'topic': g_topic, 'last_post_pk': last_post_pk, 'newpost': newpost, 'form': form, }) # Saving the message else: form = PrivatePostForm(g_topic, request.user, request.POST) if form.is_valid(): data = form.data post = PrivatePost() post.privatetopic = g_topic post.author = request.user post.text = data['text'] post.text_html = emarkdown(data['text']) post.pubdate = datetime.now() post.position_in_topic = g_topic.get_post_count() + 1 post.save() g_topic.last_message = post g_topic.save() # send email subject = "ZDS - MP : " + g_topic.title from_email = "Zeste de Savoir <{0}>".format(settings.MAIL_NOREPLY) parts = list(g_topic.participants.all()) parts.append(g_topic.author) parts.remove(request.user) for part in parts: profile = part.profile if profile.email_for_answer: pos = post.position_in_topic - 1 last_read = PrivateTopicRead.objects.filter( privatetopic=g_topic, privatepost__position_in_topic=pos, user=part).count() if last_read > 0: message_html = get_template('email/mp/new.html') \ .render( Context({ 'username': part.username, 'url': settings.SITE_URL + post.get_absolute_url(), 'author': request.user.username }) ) message_txt = get_template('email/mp/new.txt').render( Context({ 'username': part.username, 'url': settings.SITE_URL + post.get_absolute_url(), 'author': request.user.username }) ) msg = EmailMultiAlternatives( subject, message_txt, from_email, [ part.email]) msg.attach_alternative(message_html, "text/html") msg.send() return redirect(post.get_absolute_url()) else: return render_template('mp/post/new.html', { 'topic': g_topic, 'last_post_pk': last_post_pk, 'newpost': newpost, 'form': form, }) else: text = '' # Using the quote button if 'cite' in request.GET: post_cite_pk = request.GET['cite'] post_cite = PrivatePost.objects.get(pk=post_cite_pk) for line in post_cite.text.splitlines(): text = text + '> ' + line + '\n' text = u'{0}Source:[{1}]({2}{3})'.format( text, post_cite.author.username, settings.SITE_URL, post_cite.get_absolute_url()) form = PrivatePostForm(g_topic, request.user, initial={ 'text': text }) return render_template('mp/post/new.html', { 'topic': g_topic, 'posts': posts, 'last_post_pk': last_post_pk, 'form': form })
def send_mp(author, users, title, subtitle, text, send_by_mail=True, leave=True, direct=False): """Send MP at members.""" # Creating the thread n_topic = PrivateTopic() n_topic.title = title[:80] n_topic.subtitle = subtitle n_topic.pubdate = datetime.now() n_topic.author = author n_topic.save() # Add all participants on the MP. for part in users: n_topic.participants.add(part) # Addi the first message post = PrivatePost() post.privatetopic = n_topic post.author = author post.text = text post.text_html = emarkdown(text) post.pubdate = datetime.now() post.position_in_topic = 1 post.save() n_topic.last_message = post n_topic.save() # send email if send_by_mail: if direct: subject = "ZDS : " + n_topic.title from_email = "Zeste de Savoir <{0}>".format(settings.MAIL_NOREPLY) for part in users: message_html = get_template('email/mp/direct.html').render( Context({'msg': emarkdown(text)})) message_txt = get_template('email/mp/direct.txt').render( Context({'msg': text})) msg = EmailMultiAlternatives(subject, message_txt, from_email, [part.email]) msg.attach_alternative(message_html, "text/html") try: msg.send() except: msg = None else: subject = "ZDS - MP: " + n_topic.title from_email = "Zeste de Savoir <{0}>".format(settings.MAIL_NOREPLY) for part in users: message_html = get_template('email/mp/new.html').render( Context({ 'username': part.username, 'url': settings.SITE_URL + n_topic.get_absolute_url(), 'author': author.username })) message_txt = get_template('email/mp/new.txt').render( Context({ 'username': part.username, 'url': settings.SITE_URL + n_topic.get_absolute_url(), 'author': author.username })) msg = EmailMultiAlternatives(subject, message_txt, from_email, [part.email]) msg.attach_alternative(message_html, "text/html") try: msg.send() except: msg = None if leave: move = n_topic.participants.first() n_topic.author = move n_topic.participants.remove(move) n_topic.save() return n_topic
def answer(request): """Adds an answer from an user to a topic.""" try: topic_pk = request.GET["sujet"] except KeyError: raise Http404 # Retrieve current topic. g_topic = get_object_or_404(PrivateTopic, pk=topic_pk) # Retrieve 3 last posts of the currenta topic. posts = PrivatePost.objects.filter(privatetopic=g_topic).order_by("-pubdate")[:3] last_post_pk = g_topic.last_message.pk # User would like preview his post or post a new post on the topic. if request.method == "POST": data = request.POST newpost = last_post_pk != int(data["last_post"]) # Using the « preview button », the « more » button or new post if "preview" in data or newpost: form = PrivatePostForm(g_topic, request.user, initial={"text": data["text"]}) return render_template( "mp/post/new.html", {"topic": g_topic, "last_post_pk": last_post_pk, "newpost": newpost, "form": form} ) # Saving the message else: form = PrivatePostForm(g_topic, request.user, request.POST) if form.is_valid(): data = form.data post = PrivatePost() post.privatetopic = g_topic post.author = request.user post.text = data["text"] post.text_html = emarkdown(data["text"]) post.pubdate = datetime.now() post.position_in_topic = g_topic.get_post_count() + 1 post.save() g_topic.last_message = post g_topic.save() # send email subject = "ZDS - MP : " + g_topic.title from_email = "Zeste de Savoir <{0}>".format(settings.MAIL_NOREPLY) parts = list(g_topic.participants.all()) parts.append(g_topic.author) parts.remove(request.user) for part in parts: profile = part.profile if profile.email_for_answer: pos = post.position_in_topic - 1 last_read = PrivateTopicRead.objects.filter( privatetopic=g_topic, privatepost__position_in_topic=pos, user=part ).count() if last_read > 0: message_html = get_template("email/mp/new.html").render( Context( { "username": part.username, "url": settings.SITE_URL + post.get_absolute_url(), "author": request.user.username, } ) ) message_txt = get_template("email/mp/new.txt").render( Context( { "username": part.username, "url": settings.SITE_URL + post.get_absolute_url(), "author": request.user.username, } ) ) msg = EmailMultiAlternatives(subject, message_txt, from_email, [part.email]) msg.attach_alternative(message_html, "text/html") msg.send() return redirect(post.get_absolute_url()) else: return render_template( "mp/post/new.html", {"topic": g_topic, "last_post_pk": last_post_pk, "newpost": newpost, "form": form}, ) else: text = "" # Using the quote button if "cite" in request.GET: post_cite_pk = request.GET["cite"] post_cite = PrivatePost.objects.get(pk=post_cite_pk) for line in post_cite.text.splitlines(): text = text + "> " + line + "\n" text = u"{0}Source:[{1}]({2}{3})".format( text, post_cite.author.username, settings.SITE_URL, post_cite.get_absolute_url() ) form = PrivatePostForm(g_topic, request.user, initial={"text": text}) return render_template( "mp/post/new.html", {"topic": g_topic, "posts": posts, "last_post_pk": last_post_pk, "form": form} )
def answer(request): ''' Adds an answer from a user to an article ''' try: article_pk = request.GET['article'] except KeyError: raise Http404 g_article = get_object_or_404(Article, pk=article_pk) reactions = Reaction.objects.filter(article=g_article).order_by('-pubdate')[:3] if g_article.last_reaction: last_reaction_pk = g_article.last_reaction.pk else: last_reaction_pk=0 # Making sure reactioning is allowed if g_article.is_locked: raise Http404 # Check that the user isn't spamming if g_article.antispam(request.user): raise Http404 # If we just sent data if request.method == 'POST': data = request.POST newreaction = last_reaction_pk != int(data['last_reaction']) # Using the « preview button », the « more » button or new reaction if 'preview' in data or 'more' in data or newreaction: return render_template('article/answer.html', { 'text': data['text'], 'article': g_article, 'reactions': reactions, 'last_reaction_pk': last_reaction_pk, 'newreaction': newreaction }) # Saving the message else: form = ReactionForm(request.POST) if form.is_valid() and data['text'].strip() !='': data = form.data reaction = Reaction() reaction.article = g_article reaction.author = request.user reaction.text = data['text'] reaction.text_html = emarkdown(data['text']) reaction.pubdate = datetime.now() reaction.position = g_article.get_reaction_count() + 1 reaction.ip_address = get_client_ip(request) reaction.save() g_article.last_reaction = reaction g_article.save() return redirect(reaction.get_absolute_url()) else: raise Http404 else: text = '' # Using the quote button if 'cite' in request.GET: reaction_cite_pk = request.GET['cite'] reaction_cite = Reaction.objects.get(pk=reaction_cite_pk) for line in reaction_cite.text.splitlines(): text = text + '> ' + line + '\n' text = u'**{0} a écrit :**\n{1}\n'.format( reaction_cite.author.username, text) return render_template('article/answer.html', { 'article': g_article, 'text': text, 'reactions': reactions, 'last_reaction_pk': last_reaction_pk })
def publish_container( db_object, base_dir, container, template="tutorialv2/export/chapter.html", file_ext="html", image_callback=None, **ctx, ): """'Publish' a given container, in a recursive way Only here for epub publication (complexity of image/path traversal for the archive to be built) :param image_callback: callback used to change images tags on the created html :type image_callback: callable :param db_object: database representation of the content :type db_object: PublishableContent :param base_dir: directory of the top container :type base_dir: str :param template: the django template we will use to produce chapter export to html. :param container: a given container :type container: Container :param file_ext: output file extension :raise FailureDuringPublication: if anything goes wrong """ from zds.tutorialv2.models.versioned import Container from zds.tutorialv2.publication_utils import FailureDuringPublication path_to_title_dict = collections.OrderedDict() ctx["relative"] = ctx.get("relative", ".") if not isinstance(container, Container): raise FailureDuringPublication(_("Le conteneur n'en est pas un !")) # jsFiddle support is_js = "" if db_object.js_support: is_js = "js" current_dir = path.dirname( path.join(base_dir, container.get_prod_path(relative=True))) if not path.isdir(current_dir): makedirs(current_dir) img_relative_path = ".." if ctx[ "relative"] == "." else "../" + ctx["relative"] if container.has_extracts( ): # the container can be rendered in one template wrapped_image_callback = image_callback( img_relative_path) if image_callback else image_callback args = {"container": container, "is_js": is_js} args.update(ctx) args["relative"] = img_relative_path parsed = render_to_string(template, args) write_chapter_file( base_dir, container, Path(container.get_prod_path(True, file_ext)), parsed, path_to_title_dict, wrapped_image_callback, ) for extract in container.children: extract.text = None container.introduction = None container.conclusion = None else: # separate render of introduction and conclusion wrapped_image_callback_intro_ccl = image_callback( img_relative_path) if image_callback else image_callback # create subdirectory if not path.isdir(current_dir): makedirs(current_dir) relative_ccl_path = "../" + ctx.get("relative", ".") if container.introduction and container.get_introduction(): part_path = Path(container.get_prod_path(relative=True), "introduction." + file_ext) args = {"text": container.get_introduction()} args.update(ctx) args["relative"] = relative_ccl_path if ctx.get("intro_ccl_template", None): parsed = render_to_string(ctx.get("intro_ccl_template"), args) else: parsed = emarkdown(container.get_introduction(), db_object.js_support) container.introduction = str(part_path) write_chapter_file(base_dir, container, part_path, parsed, path_to_title_dict, wrapped_image_callback_intro_ccl) children = copy.copy(container.children) container.children = [] container.children_dict = {} for child in filter(lambda c: c.ready_to_publish, children): altered_version = copy.copy(child) container.children.append(altered_version) container.children_dict[altered_version.slug] = altered_version if not child.has_extracts(): ctx["relative"] = "../" + ctx["relative"] result = publish_container( db_object, base_dir, altered_version, file_ext=file_ext, image_callback=image_callback, template=template, **ctx, ) path_to_title_dict.update(result) if container.conclusion and container.get_conclusion(): part_path = Path(container.get_prod_path(relative=True), "conclusion." + file_ext) args = {"text": container.get_conclusion()} args.update(ctx) args["relative"] = relative_ccl_path if ctx.get("intro_ccl_template", None): parsed = render_to_string(ctx.get("intro_ccl_template"), args) else: parsed = emarkdown(container.get_conclusion(), db_object.js_support) container.conclusion = str(part_path) write_chapter_file(base_dir, container, part_path, parsed, path_to_title_dict, wrapped_image_callback_intro_ccl) return path_to_title_dict
def publish_container(db_object, base_dir, container): """ "Publish" a given container, in a recursive way :param db_object: database representation of the content :type db_object: PublishableContent :param base_dir: directory of the top container :type base_dir: str :param container: a given container :type container: Container :raise FailureDuringPublication: if anything goes wrong """ from zds.tutorialv2.models.models_versioned import Container if not isinstance(container, Container): raise FailureDuringPublication(_(u'Le conteneur n\'en est pas un !')) template = 'tutorialv2/export/chapter.html' # jsFiddle support if db_object.js_support: is_js = "js" else: is_js = "" current_dir = os.path.dirname( os.path.join(base_dir, container.get_prod_path(relative=True))) if not os.path.isdir(current_dir): os.makedirs(current_dir) if container.has_extracts( ): # the container can be rendered in one template parsed = render_to_string(template, { 'container': container, 'is_js': is_js }) f = codecs.open(os.path.join(base_dir, container.get_prod_path(relative=True)), 'w', encoding='utf-8') try: f.write(parsed) except (UnicodeError, UnicodeEncodeError): raise FailureDuringPublication( _(u'Une erreur est survenue durant la publication de « {} », vérifiez le code markdown' ).format(container.title)) f.close() for extract in container.children: extract.text = None container.introduction = None container.conclusion = None else: # separate render of introduction and conclusion current_dir = os.path.join( base_dir, container.get_prod_path(relative=True)) # create subdirectory if not os.path.isdir(current_dir): os.makedirs(current_dir) if container.introduction: path = os.path.join(container.get_prod_path(relative=True), 'introduction.html') f = codecs.open(os.path.join(base_dir, path), 'w', encoding='utf-8') try: f.write( emarkdown(container.get_introduction(), db_object.js_support)) except (UnicodeError, UnicodeEncodeError): raise FailureDuringPublication( _(u'Une erreur est survenue durant la publication de l\'introduction de « {} »,' u' vérifiez le code markdown').format(container.title)) container.introduction = path if container.conclusion: path = os.path.join(container.get_prod_path(relative=True), 'conclusion.html') f = codecs.open(os.path.join(base_dir, path), 'w', encoding='utf-8') try: f.write( emarkdown(container.get_conclusion(), db_object.js_support)) except (UnicodeError, UnicodeEncodeError): raise FailureDuringPublication( _(u'Une erreur est survenue durant la publication de la conclusion de « {} »,' u' vérifiez le code markdown').format(container.title)) container.conclusion = path for child in container.children: publish_container(db_object, base_dir, child)
def perform_update(self, instance, data): instance.text = data.get('text') instance.text_html = emarkdown(data.get('text')) instance.update = datetime.now() instance.save() return instance