def migrate_to_new_editor(self): skip = 0 while True: query = 'MATCH (m:Mission) RETURN m SKIP %s LIMIT 25' % skip skip += 24 res, _ = db.cypher_query(query) if not res.one: break for mission in [Mission.inflate(row[0]) for row in res]: rendered = render_content( markdown.markdown(mission.epic.replace( '>', '>')).replace('<a', '<a target="_blank"')) mission.epic = rendered mission.temp_epic = rendered mission.save() skip = 0 while True: query = 'MATCH (m:Question) RETURN m SKIP %s LIMIT 25' % skip skip += 24 res, _ = db.cypher_query(query) if not res.one: break for question in [Question.inflate(row[0]) for row in res]: rendered = render_content( markdown.markdown(question.content.replace( '>', '>')).replace('<a', '<a target="_blank"')) question.content = rendered question.save() skip = 0 while True: query = 'MATCH (m:Solution) RETURN m SKIP %s LIMIT 25' % skip skip += 24 res, _ = db.cypher_query(query) if not res.one: break for solution in [Solution.inflate(row[0]) for row in res]: rendered = render_content( markdown.markdown(solution.content.replace( '>', '>')).replace('<a', '<a target="_blank"')) solution.content = rendered solution.save() skip = 0 while True: query = 'MATCH (m:Update) RETURN m SKIP %s LIMIT 25' % skip skip += 24 res, _ = db.cypher_query(query) if not res.one: break for update in [Update.inflate(row[0]) for row in res]: rendered = render_content( markdown.markdown(update.content.replace( '>', '>')).replace('<a', '<a target="_blank"')) update.content = rendered update.save() cache.set("migrated_to_new_editor", True)
def test_remove_class_and_remove_caption_placeholder(self): content = '<div><figcaption class="medium-insert-caption-placeholder' \ '"></figcaption></div>' \ '<div class="medium-insert-embeds-selected"></div>' rendered_content = '<div></div><div class=""></div>' res = render_content(content) self.assertEqual(rendered_content, res)
def test_with_medium_editor_embeds_selected(self): content = '<div class="some-other-class this-should-stay ' \ 'medium-insert-embeds-selected">Some test content</div>' rendered_content = '<div class="some-other-class this-should-stay">' \ 'Some test content</div>' res = render_content(content) self.assertEqual(rendered_content, res)
def create(self, validated_data): request = self.context["request"] # Note that DRF requires us to use the source as the key here but # tags prior to serializing mission = None tags = validated_data.pop('get_tags', []) owner = Pleb.get(request.user.username) mission_id = validated_data.get('mission', '') if mission_id: mission = Mission.get(mission_id) validated_data['owner_username'] = owner.username uuid = str(uuid1()) validated_data['content'] = render_content( validated_data.get('content', "")) url = reverse('question_detail_page', kwargs={ 'question_uuid': uuid, "slug": slugify(validated_data['title']) }, request=request) href = reverse('question-detail', kwargs={'object_uuid': uuid}, request=request) soup = BeautifulSoup(validated_data['content'], "lxml").get_text() question = Question(url=url, href=href, object_uuid=uuid, summary=smart_truncate(soup), **validated_data).save() question.owned_by.connect(owner) if mission is not None: mission.associated_with.connect(question) for tag in tags: query = 'MATCH (t:Tag {name:"%s"}) WHERE NOT t:AutoTag ' \ 'RETURN t' % slugify(tag) res, _ = db.cypher_query(query) if not res.one: if (request.user.username == "devon_bleibtrey" or request.user.username == "tyler_wiersing" or owner.reputation >= 1250): tag_obj = Tag(name=slugify(tag)).save() question.tags.connect(tag_obj) else: continue else: tag_obj = Tag.inflate(res.one) question.tags.connect(tag_obj) spawn_task(task_func=update_tags, task_param={"tags": tags}) if validated_data.get('external_location_id', None) is not None: spawn_task( task_func=create_location_tree, task_param={"external_id": question.external_location_id}) spawn_task(task_func=add_auto_tags_to_question_task, task_param={"object_uuid": question.object_uuid}) spawn_task(task_func=create_question_summary_task, task_param={'object_uuid': question.object_uuid}) question.refresh() cache.set(question.object_uuid, question) return question
def update(self, instance, validated_data): validate_is_owner(self.context.get('request', None), instance) instance.title = validated_data.pop('title', instance.title) instance.content = render_content( validated_data.pop('content', instance.content)) instance.last_edited_on = datetime.now(pytz.utc) instance.save() return instance
def update(self, instance, validated_data): validate_is_owner(self.context.get('request', None), instance) instance.content = render_content( validated_data.get('content', instance.content)) instance.last_edited_on = datetime.now(pytz.utc) instance.save() spawn_task(task_func=create_solution_summary_task, task_param={'object_uuid': instance.object_uuid}) return instance
def test_create_with_h2_first(self): content = "<h2> hello world this is a h2 </h2><br>" \ "<h3> with a h3 after it </h3><br>" \ "<h2 another h2 </h2><br>" \ "and then some text" rendered_content = '<h2 style="padding-top: 0; margin-top: 5px;"> ' \ 'hello world this is a h2 </h2><br/><h3> with a ' \ 'h3 after it </h3><br/><h2 another="" h2=""><br/>' \ 'and then some text</h2>' res = render_content(content) self.assertEqual(res, rendered_content)
def create(self, validated_data): # TODO we don't have a way currently to distinguish what a Update is # about. Think it'll be based on an attribute submitted by the front # end. That will be based on where it's at (make update from Public # Office Mission vs Advocate Mission vs Quest vs etc) request, _, _, _, _ = gather_request_data(self.context) quest = validated_data.pop('quest', None) owner = Pleb.get(request.user.username) validated_data['owner_username'] = owner.username about = validated_data.pop('about', None) about_type = validated_data.get('about_type') validated_data['content'] = \ render_content(validated_data.get('content', '')) update = Update(**validated_data).save() quest.updates.connect(update) url = None if about_type == 'mission': update.mission.connect(about) url = reverse('mission_updates', kwargs={ 'object_uuid': about.object_uuid, 'slug': slugify(about.get_mission_title()) }) elif about_type == 'quest': update.quest.connect(about) cache.delete("%s_updates" % quest.object_uuid) task_params = { "sb_object": update.object_uuid, "to_plebs": quest.get_followers(), "from_pleb": request.user.username, "notification_id": str(uuid1()), "url": url, "action_name": "%s %s has made an Update on a Quest you follow!" % (request.user.first_name, request.user.last_name), "public": True } spawn_task(task_func=spawn_notifications, task_param=task_params) return update
def test_with_medium_editor_insert_plus(self): content = '<div><p>hello world</p><p style="text-align: center;" ' \ 'class="medium-insert-active"><i><br></i></p></div>' \ '<div class="medium-insert-buttons" ' \ 'contenteditable="false" style="left: 35px; top: 1007px; ' \ 'display: block;">' \ '<a class="medium-insert-buttons-show">+</a>' \ '<ul class="medium-insert-buttons-addons" ' \ 'style="display: none">' \ '<li><a data-addon="images" ' \ 'data-action="add" class="medium-insert-action">' \ '<span class="fa fa-camera"></span></a></li>' \ '<li><a data-addon="embeds" data-action="add" ' \ 'class="medium-insert-action"><span class="fa ' \ 'fa-youtube-play"></span></a></li>' \ '</ul></div><div><p>end world</p></div>' rendered_content = '<div><p>hello world</p><p ' \ 'class="medium-insert-active" style="text-align: ' \ 'center;"><i><br/></i></p></div><div>' \ '<p>end world</p></div>' res = render_content(content) self.assertEqual(res, rendered_content)
def create(self, validated_data): request = self.context["request"] question = validated_data.pop('question', None) owner = Pleb.get(request.user.username) validated_data['owner_username'] = owner.username uuid = str(uuid1()) validated_data['content'] = render_content( validated_data.get('content', "")) href = reverse('solution-detail', kwargs={"object_uuid": uuid}, request=request) soup = BeautifulSoup(validated_data['content'], "lxml").get_text() solution = Solution(url=question.url, href=href, object_uuid=uuid, parent_id=question.object_uuid, summary=smart_truncate(soup), **validated_data).save() solution.owned_by.connect(owner) question.solutions.connect(solution) spawn_task(task_func=create_solution_summary_task, task_param={'object_uuid': solution.object_uuid}) return solution
def update(self, instance, validated_data): # TODO do we want to allow for tags to be changed? # I don't think we do because of the tight coupling with Reputation # and search. I think it could be exploited too easily. """ When we start doing versioning: edit = Question(title=validated_data.get('title', instance.title), content=validated_data.get('content', instance.content)) edit.save() instance.edits.connect(edit) edit.edit_to.connect(instance) """ validate_is_owner(self.context.get('request', None), instance) instance.title = validated_data.get('title', instance.title) instance.content = render_content( validated_data.get('content', instance.content)) instance.last_edited_on = datetime.now(pytz.utc) instance.latitude = validated_data.get('latitude', instance.latitude) instance.longitude = validated_data.get('longitude', instance.longitude) instance.affected_area = validated_data.get('affected_area', instance.affected_area) instance.external_location_id = validated_data.get( 'external_location_id', instance.external_location_id) instance.save() cache.delete(instance.object_uuid) if validated_data.get('external_location_id', None) is not None: spawn_task( task_func=create_location_tree, task_param={"external_id": instance.external_location_id}) spawn_task(task_func=add_auto_tags_to_question_task, task_param={"object_uuid": instance.object_uuid}) spawn_task(task_func=create_question_summary_task, task_param={'object_uuid': instance.object_uuid}) return super(QuestionSerializerNeo, self).update(instance, validated_data)
def test_with_medium_editor_caption_placeholder(self): content = '<div><figcaption class="medium-insert-caption-placeholder' \ '"></figcaption></div>' rendered_content = "<div></div>" res = render_content(content) self.assertEqual(rendered_content, res)
def test_none(self): res = render_content(None) self.assertEqual(res, "")
def test_no_text(self): res = render_content("") self.assertEqual("", res)
def update(self, instance, validated_data): from sb_base.serializers import validate_is_owner validate_is_owner(self.context.get('request', None), instance) instance.completed = validated_data.pop( 'completed', instance.completed) initial_review_state = instance.submitted_for_review instance.submitted_for_review = validated_data.pop( 'submitted_for_review', instance.submitted_for_review) instance.shared_on_facebook = validated_data.get( 'shared_on_facebook', instance.shared_on_facebook) instance.shared_on_twitter = validated_data.get( 'shared_on_twitter', instance.shared_on_twitter) instance.saved_for_later = validated_data.get('saved_for_later', instance.saved_for_later) if instance.submitted_for_review and not initial_review_state and not \ instance.saved_for_later: serializer = IntercomEventSerializer( data={'event_name': "submit-mission-for-review", 'username': instance.owner_username}) if serializer.is_valid(): serializer.save() message_data = { 'message_type': 'email', 'subject': 'Submit Mission For Review', 'body': 'Hi Team,\n%s has submitted their %s Mission. ' 'Please review it in the <a href="%s">' 'council area</a>. ' % (instance.owner_username, instance.title, reverse('council_missions', request=self.context.get('request'))), 'template': "personal", 'from_user': { 'type': "admin", 'id': settings.INTERCOM_ADMIN_ID_DEVON}, 'to_user': { 'type': "user", 'user_id': settings.INTERCOM_USER_ID_DEVON} } serializer = IntercomMessageSerializer(data=message_data) if serializer.is_valid(): serializer.save() db.cypher_query( 'MATCH (mission:Mission {object_uuid: "%s"})-' '[:MUST_COMPLETE]->(task:OnboardingTask {title: "%s"}) ' 'SET task.completed=true RETURN task' % ( instance.object_uuid, settings.SUBMIT_FOR_REVIEW)) title = validated_data.pop('title', instance.title) if instance.submitted_for_review and instance.review_feedback \ and validated_data.get('epic', '') and not instance.active: message_data = { 'message_type': 'email', 'subject': 'Problem Mission Updated', 'body': render_to_string( "email_templates/problem_mission_updates.html", context={"username": instance.owner_username, "council_url": reverse('council_missions', request=self.context.get('request')), "title": instance.title}, request=self.context.get('request')), 'template': "personal", 'from_user': { 'type': "admin", 'id': settings.INTERCOM_ADMIN_ID_DEVON}, 'to_user': { 'type': "user", 'user_id': settings.INTERCOM_USER_ID_DEVON} } serializer = IntercomMessageSerializer(data=message_data) if serializer.is_valid(): serializer.save() if empty_text_to_none(title) is not None: instance.title = title instance.about = empty_text_to_none( validated_data.get('about', instance.about)) if instance.about is not None: db.cypher_query( 'MATCH (mission:Mission {object_uuid: "%s"})-' '[:MUST_COMPLETE]->(task:OnboardingTask {title: "%s"}) ' 'SET task.completed=true RETURN task' % ( instance.object_uuid, settings.MISSION_ABOUT_TITLE)) instance.epic = remove_smart_quotes( validated_data.pop('epic', instance.epic)) # We expect the epic to be set to None and not "" so that None # can be used in this function for checks and the templates. instance.epic = empty_text_to_none(render_content(instance.epic)) prev_temp_epic = instance.temp_epic instance.temp_epic = remove_smart_quotes(validated_data.pop( 'temp_epic', instance.temp_epic)) instance.temp_epic = empty_text_to_none( render_content(instance.temp_epic)) if prev_temp_epic != instance.temp_epic: instance.epic_last_autosaved = datetime.now(pytz.utc) if instance.epic is not None: db.cypher_query( 'MATCH (mission:Mission {object_uuid: "%s"})-' '[:MUST_COMPLETE]->(task:OnboardingTask {title: "%s"}) ' 'SET task.completed=true RETURN task' % ( instance.object_uuid, settings.EPIC_TITLE)) instance.facebook = clean_url( validated_data.get('facebook', instance.facebook)) instance.linkedin = clean_url( validated_data.get('linkedin', instance.linkedin)) instance.youtube = clean_url( validated_data.get('youtube', instance.youtube)) instance.twitter = clean_url( validated_data.get('twitter', instance.twitter)) instance.website = clean_url( validated_data.get('website', instance.website)) instance.wallpaper_pic = validated_data.pop('wallpaper_pic', instance.wallpaper_pic) if instance.shared_on_facebook: db.cypher_query( 'MATCH (mission:Mission {object_uuid: "%s"})-' '[:MUST_COMPLETE]->(task:OnboardingTask {title: "%s"}) ' 'SET task.completed=true RETURN task' % ( instance.object_uuid, settings.SHARE_ON_FACEBOOK)) if instance.shared_on_twitter: db.cypher_query( 'MATCH (mission:Mission {object_uuid: "%s"})-' '[:MUST_COMPLETE]->(task:OnboardingTask {title: "%s"}) ' 'SET task.completed=true RETURN task' % ( instance.object_uuid, settings.SHARE_ON_TWITTER)) if settings.DEFAULT_WALLPAPER not in instance.wallpaper_pic: db.cypher_query( 'MATCH (mission:Mission {object_uuid: "%s"})-' '[:MUST_COMPLETE]->(task:OnboardingTask {title: "%s"}) ' 'SET task.completed=true RETURN task' % ( instance.object_uuid, settings.MISSION_WALLPAPER_TITLE)) instance.save() cache.set("%s_mission" % instance.object_uuid, instance) if instance.active: return super(MissionSerializer, self).update( instance, validated_data) return instance