def update(self, instance, validated_data): task_param = { "object_uuid": instance.object_uuid, "label": instance.get_child_label().lower() } spawn_task(task_func=update_search_object, task_param=task_param) return instance
def create(self, request, *args, **kwargs): wall_pleb = Pleb.get(self.kwargs[self.lookup_field]) friend_with = wall_pleb.is_friends_with(request.user.username) if friend_with is False and wall_pleb.username != request.user.username: return Response( {"detail": "Sorry you are not friends with this" " person."}, status=status.HTTP_400_BAD_REQUEST) serializer = self.get_serializer(data=request.data) if serializer.is_valid(): instance = serializer.save(wall_owner_profile=wall_pleb) spawn_task(task_func=spawn_notifications, task_param={ "from_pleb": request.user.username, "sb_object": serializer.data['object_uuid'], "url": reverse('single_post_page', kwargs={ "object_uuid": serializer.data["object_uuid"] }), "to_plebs": [ self.kwargs[self.lookup_field], ], "notification_id": str(uuid1()), "action_name": instance.action_name }) return Response(serializer.data, status=status.HTTP_200_OK) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def create(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data, context={"request": request}) if serializer.is_valid(): question = Question.nodes.get( object_uuid=self.kwargs[self.lookup_field]) instance = serializer.save(question=question) query = "MATCH (a:Question {object_uuid:'%s'})-[:OWNED_BY]->" \ "(b:Pleb) RETURN b" % (self.kwargs[self.lookup_field]) res, col = db.cypher_query(query) question_owner = Pleb.inflate(res[0][0]) serializer = serializer.data to_plebs = [question_owner.username] mission = question.get_mission(question.object_uuid) if mission: to_plebs.append(mission['owner_username']) spawn_task(task_func=spawn_notifications, task_param={ "from_pleb": request.user.username, "sb_object": serializer['object_uuid'], "url": reverse( 'single_solution_page', kwargs={"object_uuid": serializer["object_uuid"]}), # TODO discuss notifying all the people who have provided # solutions on a given question. "to_plebs": to_plebs, "notification_id": str(uuid1()), 'action_name': instance.action_name }) # Not going to add until necessary for search # spawn_task(task_func=add_solution_to_search_index, # task_param={"solution": serializer}) return Response(serializer, status=status.HTTP_200_OK) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def create(self, validated_data): request, _, _, _, _ = gather_request_data(self.context) stripe.api_key = settings.STRIPE_SECRET_KEY stripe.api_version = settings.STRIPE_API_VERSION donor = Pleb.get(request.user.username) token = validated_data.pop('token', None) # TODO add payment_method selection support to direct donations # this pop is just to allow the donation to save using **validated_data validated_data.pop('payment_method', None) donation = Donation(owner_username=donor.username, **validated_data).save() if not donor.stripe_customer_id: customer = stripe.Customer.create( description="Customer for %s" % donor.username, card=token, email=donor.email) donor.stripe_customer_id = customer['id'] donor.save() cache.delete(donor.username) donor.refresh() donor.donations.connect(donation) donation.owned_by.connect(donor) charge = stripe.Charge.create( amount=donation.amount, currency="usd", customer=donor.stripe_customer_id, receipt_email=donor.email, description="Donation to Sagebrew from %s" % donor.username ) donation.stripe_charge_id = charge['id'] donation.save() spawn_task(task_func=check_privileges, task_param={"username": donor.username}) return donation
def spawn_user_updates(username, object_uuid): from sb_votes.tasks import vote_object_task vote_res = [] try: vote_res.append(get_user_updates(username=username, object_uuid=object_uuid, table_name='votes')) except JSONResponseError as e: raise spawn_user_updates.retry(exc=e, countdown=10, max_retries=None) except(TypeError, IOError, BotoClientError, BotoServerError, AWSConnectionError, Exception) as e: raise spawn_user_updates.retry(exc=e, countdown=45, max_retries=None) for item in vote_res: try: item['status'] = int(item['status']) task_data = { 'vote_type': item['status'], 'current_pleb': username, 'object_uuid': item['parent_object'], } spawn_task(task_func=vote_object_task, task_param=task_data) except KeyError: pass return True
def migrate_questions(self): query = 'MATCH (a:Question) RETURN a' res, _ = db.cypher_query(query) for question in [Question.inflate(row[0]) for row in res]: spawn_task(task_func=create_question_summary_task, task_param={'object_uuid': question.object_uuid}) self.stdout.write("completed question migration\n", ending='')
def create(self, request, *args, **kwargs): object_uuid = self.kwargs[self.lookup_field] now = str(datetime.now(pytz.utc)) vote_data = request.data serializer = self.get_serializer(data=vote_data, context={"request": request}) if not Pleb.get(request.user.username).is_verified: return Response( { "detail": "Sorry, you cannot vote unless you are verified!", "status": status.HTTP_401_UNAUTHORIZED, "developer_message": "A user can only vote on content " "if they are verified." }, status=status.HTTP_401_UNAUTHORIZED) if serializer.is_valid(): parent_object_uuid = self.kwargs[self.lookup_field] vote_status = int(serializer.validated_data['vote_type']) handle_vote(parent_object_uuid, vote_status, request.user.username, now) async_result = cache.get("%s_%s_vote" % (request.user.username, object_uuid)) task_params = { "username": request.user.username, "object_uuid": object_uuid } if async_result is not None: # if there is already a task lined up, # revoke it and spawn a new one async_result.revoke() # spawn a task which will execute 30 seconds from now # potential improvement here is to have a way to detect if the new_task = spawn_task(spawn_user_updates, task_param=task_params, countdown=30) cache.set("%s_%s_vote" % (request.user.username, object_uuid), new_task) search_result = cache.get("%s_vote_search_update" % object_uuid) if search_result is not None: search_result.revoke() task_param = {"object_uuid": object_uuid} spawned = spawn_task(task_func=update_search_object, task_param=task_param, countdown=10) cache.set("%s_vote_search_update" % object_uuid, spawned) return Response({ "detail": "Successfully created or modified " "vote.", "status": status.HTTP_200_OK, "developer_message": None }) else: return Response(serializer.errors, status=400)
def get_queryset(self): filter_type = self.request.query_params.get("filter", "general") query_param = self.request.query_params.get("query", "") search_type_dict = dict(settings.SEARCH_TYPES) alchemyapi = AlchemyAPI() response = alchemyapi.keywords("text", query_param) # this .get on a dict is a temporary work around for the alchemyapi # package not having any exception handling, this will keep us safe # from key errors caused by us hitting the alchemy endpoint too much # and using up our allowed requests keywords = response.get('keywords', []) # TODO surround ES query with proper exception handling and ensure # each one is handled correctly es = Elasticsearch(settings.ELASTIC_SEARCH_HOST) # TODO run query_param through natural language processor, determine # if what they have searched is an email address or a name so that # the first search result is that user # TODO implement filtering on auto generated keywords from alchemyapi if filter_type is None or filter_type == 'general': res = es.search(index='full-search-base', size=50, body={ "query": { "multi_match": { "fields": settings.SEARCH_FIELDS, "query": query_param, "fuzziness": "AUTO", "phrase_slop": 2 } } }) else: try: res = es.search(index='full-search-base', size=50, doc_type=search_type_dict[filter_type], body={ "query": { "multi_match": { "fields": settings.SEARCH_FIELDS, "query": query_param, "fuzziness": "AUTO", "phrase_slop": 2 } } }) except KeyError: raise ValidationError("Invalid filter parameter") task_param = { "username": self.request.user.username, "query_param": query_param, "keywords": keywords } # we do not notify users if this task fails to spawn because it is # just for us later down the line spawn_task(task_func=update_search_query, task_param=task_param) return res['hits']['hits']
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 migrate_solutions(self): query = 'MATCH (a:Solution)<-[:POSSIBLE_ANSWER]-(b:Question) ' \ 'SET a.parent_id=b.object_uuid RETURN a' res, _ = db.cypher_query(query) for solution in [Solution.inflate(row[0]) for row in res]: spawn_task(task_func=create_solution_summary_task, task_param={ 'object_uuid': solution.object_uuid }) self.stdout.write("completed solution migration\n", ending='')
def create(self, validated_data): from_user = validated_data.pop('from_user', None) to_user = validated_data.pop('to_user', None) validated_data['from'] = from_user validated_data['to'] = to_user spawn_task(task_func=create_email, task_param={"message_data": validated_data}) validated_data['from_user'] = from_user validated_data['to_user'] = to_user return validated_data
def connect_to_state_districts(object_uuid): try: address = Address.nodes.get(object_uuid=object_uuid) except (DoesNotExist, Address.DoesNotExist, CypherException, IOError, ClientError) as e: raise connect_to_state_districts.retry(exc=e, countdown=3, max_retries=None) try: lookup_url = settings.OPENSTATES_DISTRICT_SEARCH_URL % \ (address.latitude, address.longitude) \ + "&apikey=53f7bd2a41df42c082bb2f07bd38e6aa" except TypeError: # in case an address doesn't have a latitude or longitude return False response = requests.get( lookup_url, headers={"content-type": 'application/json; charset=utf8'}) response_json = response.json() try: for rep in response_json: try: sector = 'state_%s' % rep['chamber'] query = 'MATCH (l:Location {name: "%s", sector:"federal"})-' \ '[:ENCOMPASSES]->(district:Location {name:"%s", ' \ 'sector:"%s"}) RETURN district ' % \ (us.states.lookup(address.state).name, rep['district'], sector) res, _ = db.cypher_query(query) except KeyError: return False try: res = res[0] except IndexError as e: raise connect_to_state_districts.retry(exc=e, countdown=3, max_retries=None) try: state_district = Location.inflate(res.district) except (CypherException, ClientError, IOError, CouldNotCommit) as e: raise connect_to_state_districts.retry(exc=e, countdown=3, max_retries=None) if state_district not in address.encompassed_by: address.encompassed_by.connect(state_district) spawn_task(task_func=create_and_attach_state_level_reps, task_param={"rep_data": response_json}) return True except (CypherException, IOError, ClientError, CouldNotCommit) as e: raise connect_to_state_districts.retry(exc=e, countdown=3, max_retries=None)
def update(self, instance, validated_data): pleb = validated_data.get('pleb', None) vote_type = validated_data.get('vote_type', None) query = 'MATCH (s:SBContent {object_uuid:"%s"})-[:COUNCIL_VOTE]->' \ '(p:Pleb) RETURN p' % instance.object_uuid res, _ = db.cypher_query(query) if not res: instance.initial_vote_time = datetime.now(pytz.utc) instance.save() res = instance.council_vote(vote_type, pleb) spawn_task(task_func=update_closed_task, task_param={'object_uuid': instance.object_uuid}) return 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 create(self, request, *args, **kwargs): if "tags" in request.data: if isinstance(request.data['tags'], basestring): request.data['tags'] = request.data['tags'].split(',') serializer = self.get_serializer(data=request.data, context={"request": request}) if serializer.is_valid(): instance = serializer.save(mission=request.data.get('mission', '')) spawn_task(task_func=update_search_object, task_param={ "object_uuid": instance.object_uuid, "label": "question" }) return Response(serializer.data, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def create_location_tree(external_id): hierarchy = cache.get(external_id) try: if hierarchy is None: raise KeyError("Could not find external id") except KeyError as e: raise create_location_tree.retry(exc=e, countdown=10, max_retries=None) end_node = parse_google_places(hierarchy['address_components'], external_id) spawn_task(task_func=connect_location_to_element, task_param={ "element_id": external_id, "location": end_node }) return end_node
def add_auto_tags(object_uuid, tag_list): """ This function creates the auto generated tag nodes and connects them to the post from which they were tagged. :param object_uuid :param tag_list: :return: """ if len(tag_list) < 1: return True content = TaggableContent.nodes.get(object_uuid=object_uuid) response = content.add_auto_tags(tag_list) if isinstance(response, Exception) is True: # pragma: no cover # Not covering as we don't have a consistent way of reproducing it # currently. - Devon Bleibtrey raise add_auto_tags.retry(exc=response, countdown=3, max_retries=None) spawned = spawn_task( task_func=create_tag_relations, task_param={"tag_array": [tag.object_uuid for tag in response]}) if isinstance(spawned, Exception) is True: # pragma: no cover # Not covering as we don't have a consistent way of reproducing it # currently. - Devon Bleibtrey raise add_auto_tags.retry(exc=response, countdown=3, max_retries=None) return response
def check_closed_reputation_changes(): """ This will be called in a task which is run either everyday or every other day and will check which objects need to be closed :return: """ try: for pleb in Pleb.nodes.all(): res = pleb.get_total_rep() cache.delete(pleb.username) if res['previous_rep'] != res['total_rep']: spawn_task(task_func=check_privileges, task_param={'username': pleb.username}) return True except (CypherException, IOError, ClientError) as e: return e
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 finalize_citizen_creation(username): try: pleb = Pleb.get(username=username, cache_buster=True) except (DoesNotExist, Exception) as e: raise finalize_citizen_creation.retry(exc=e, countdown=10, max_retries=None) task_list = {} task_data = {"object_uuid": pleb.object_uuid, "label": "pleb"} task_list["add_object_to_search_index"] = spawn_task( task_func=update_search_object, task_param=task_data, countdown=30) task_list["check_privileges_task"] = spawn_task( task_func=check_privileges, task_param={"username": username}, countdown=20) cache.delete(pleb.username) return task_list
def update(self, instance, validated_data): instance.street = validated_data.get('street', instance.street) instance.street_additional = validated_data.get( 'street_additional', instance.street_additional) instance.city = validated_data.get("city", instance.city) instance.state = us.states.lookup( validated_data.get("state", instance.state)).name instance.postal_code = validated_data.get("postal_code", instance.postal_code) instance.country = validated_data.get("country", instance.country) instance.congressional_district = validated_data.get( "congressional_district", instance.congressional_district) instance.latitude = validated_data.get("latitude", instance.latitude) instance.longitude = validated_data.get("longitude", instance.longitude) instance.save() spawn_task(task_func=update_address_location, task_param={"object_uuid": instance.object_uuid}) return instance
def update_search_query(username, query_param, keywords): """ This task creates a search query node then calls the task to create and attach keyword nodes to the search query node :param username: :param query_param: :param keywords: :return: """ try: res, _ = db.cypher_query("MATCH (a:Pleb {username:'******'}) RETURN a" % username) if res.one: res.one.pull() pleb = Pleb.inflate(res.one) else: raise update_search_query.retry(exc=DoesNotExist( "Profile with username: "******"%s does not exist" % username), countdown=3, max_retries=None) except (CypherException, IOError) as e: raise update_search_query.retry(exc=e, countdown=3, max_retries=None) try: search_query = SearchQuery.nodes.get(search_query=query_param) if pleb.searches.is_connected(search_query): rel = pleb.searches.relationship(search_query) rel.times_searched += 1 rel.last_searched = datetime.now(pytz.utc) rel.save() return True else: rel = pleb.searches.connect(search_query) rel.save() search_query.searched_by.connect(pleb) return True except (SearchQuery.DoesNotExist, DoesNotExist): search_query = SearchQuery(search_query=query_param) search_query.save() search_query.searched_by.connect(pleb) rel = pleb.searches.connect(search_query) rel.save() for keyword in keywords: keyword['query_param'] = query_param spawned = spawn_task(task_func=create_keyword, task_param=keyword) if isinstance(spawned, Exception) is True: return spawned return True except (CypherException, IOError) as e: raise update_search_query.retry(exc=e, countdown=3, max_retries=None) except Exception as e: raise update_search_query.retry(exc=e, countdown=3, max_retries=None)
def set_encompassing(self): from .tasks import connect_to_state_districts try: encompassed_by = Location.nodes.get(name=self.city) if Location.get_single_encompassed_by( encompassed_by.object_uuid) != \ us.states.lookup(self.state).name: # if a location node exists with an incorrect encompassing # state raise DoesNotExist("This Location does not exist") except (Location.DoesNotExist, DoesNotExist): encompassed_by = Location(name=self.city, sector="local").save() try: city_encompassed = Location.nodes.get( name=us.states.lookup(self.state).name) except (Location.DoesNotExist, DoesNotExist): city_encompassed = Location(name=us.states.lookup( self.state).name, sector="federal").save() if city_encompassed not in encompassed_by.encompassed_by: encompassed_by.encompassed_by.connect(city_encompassed) if encompassed_by not in city_encompassed.encompasses: city_encompassed.encompasses.connect(encompassed_by) except (MultipleNodesReturned, Exception): query = 'MATCH (l1:Location {name:"%s"})-[:ENCOMPASSED_BY]->' \ '(l2:Location {name:"%s"}) RETURN l1' % \ (self.city, self.state) res, _ = db.cypher_query(query) if res.one is not None: encompassed_by = Location.inflate(res.one) else: encompassed_by = None if encompassed_by is not None: if encompassed_by not in self.encompassed_by: self.encompassed_by.connect(encompassed_by) # get or create the state level districts and attach them to the # address spawn_task(task_func=connect_to_state_districts, task_param={'object_uuid': self.object_uuid}) return self
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 create(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data) if serializer.is_valid(): pleb = Pleb.get(request.user.username) parent_object = SBContent.nodes.get( object_uuid=self.kwargs[self.lookup_field]) instance = serializer.save(owner=pleb, parent_object=parent_object) serializer_data = serializer.data serializer_data['comment_on'] = reverse( '%s-detail' % parent_object.get_child_label().lower(), kwargs={'object_uuid': parent_object.object_uuid}, request=request) serializer_data['url'] = parent_object.get_url(request=request) notification_id = str(uuid1()) spawn_task(task_func=spawn_comment_notifications, task_param={ 'from_pleb': request.user.username, 'parent_object_uuid': self.kwargs[self.lookup_field], 'object_uuid': instance.object_uuid, 'notification_id': notification_id, 'comment_on_comment_id': str(uuid1()) }) return Response(serializer_data, status=status.HTTP_200_OK) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def update_reputation(username): try: pleb = Pleb.get(username=username, cache_buster=True) except (Pleb.DoesNotExist, DoesNotExist, CypherException, IOError) as e: raise update_reputation.retry(exc=e, countdown=3, max_retries=None) res = pleb.get_total_rep() if isinstance(res, Exception): raise update_reputation.retry(exc=res, countdown=3, max_retries=None) if res['previous_rep'] != res['total_rep']: pleb.reputation_update_seen = False pleb.save() check_priv = spawn_task(task_func=check_privileges, task_param={"username": username}) cache.delete(username) if isinstance(check_priv, Exception): raise update_reputation.retry(exc=check_priv, countdown=3, max_retries=None) return True
def create_wall_task(username=None): from sb_wall.neo_models import Wall try: query = 'MATCH (pleb:Pleb {username: "******"})' \ '-[:OWNS_WALL]->(wall:Wall) RETURN wall' % username res, _ = db.cypher_query(query) if res.one is None: wall = Wall(wall_id=str(uuid1())).save() query = 'MATCH (pleb:Pleb {username: "******"}),' \ '(wall:Wall {wall_id: "%s"}) ' \ 'CREATE UNIQUE (pleb)-[:OWNS_WALL]->(wall) ' \ 'RETURN wall' % (username, wall.wall_id) res, _ = db.cypher_query(query) spawned = spawn_task(task_func=finalize_citizen_creation, task_param={"username": username}) if isinstance(spawned, Exception) is True: raise create_wall_task.retry(exc=spawned, countdown=3, max_retries=None) except (CypherException, IOError, ClientError) as e: raise create_wall_task.retry(exc=e, countdown=3, max_retries=None) return spawned
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 create(self, validated_data): from sb_gifts.neo_models import Giftlist from sb_quests.neo_models import Quest, Position request, _, _, _, _ = gather_request_data(self.context) query = 'MATCH (quest:Quest {owner_username: "******"}) WITH quest ' \ 'OPTIONAL MATCH (quest)-[:EMBARKS_ON]->' \ '(mission:Mission) RETURN quest, ' \ 'count(mission) as mission_count' % request.user.username res, _ = db.cypher_query(query) if res.one is not None: quest = Quest.inflate(res.one['quest']) if quest.account_type == "free": if res.one['mission_count'] >= settings.FREE_MISSIONS: raise serializers.ValidationError( {"detail": "Sorry free Quests can only " "have 5 Missions.", "developer_message": "", "status_code": status.HTTP_400_BAD_REQUEST}) else: raise serializers.ValidationError( {"detail": "We couldn't find a Quest for this " "Mission. Please contact us if this " "problem continues.", "developer_message": "", "status_code": status.HTTP_404_NOT_FOUND}) add_district = "" focus_type = validated_data.get('focus_on_type') level = validated_data.get('level') # Properly Title the case of the following words in the location name location = validated_data.get('location_name') if location is not None: location = location.replace( " Of", " of").replace(" And", " and").replace(" Or", " or") focused_on = validated_data.get('focus_name') if focus_type == "advocacy": focused_on = slugify(focused_on) else: focused_on = slugify( focused_on).title().replace('-', ' ').replace('_', ' ') district = validated_data.get('district') formatted_location_name = validated_data.get('formatted_location_name') # TODO what happens if a moderator makes the mission? owner_username = request.user.username title = focused_on.title().replace('-', ' ').replace('_', ' ') mission = Mission(owner_username=owner_username, level=level, focus_on_type=focus_type, focus_name=focused_on, title=title, wallpaper_pic=static( 'images/wallpaper_capitol_2.jpg'), formatted_location_name=formatted_location_name)\ .save() giftlist = Giftlist().save() giftlist.mission.connect(mission) if focus_type == "position": if level == "federal": if district: loc_query = '(:Location {name: ' \ '"United States of America"})' \ '-[:ENCOMPASSES]->(:Location {name: "%s"})' \ '-[:ENCOMPASSES]->(location:Location ' \ '{name: "%s", sector: "federal"})' % ( location, district) elif location and focused_on != "President": loc_query = '(:Location {name: ' \ '"United States of America"})' \ '-[:ENCOMPASSES]->' \ '(location:Location {name: "%s"})' % location else: loc_query = '(location:Location {name: ' \ '"United States of America"})' elif level == "state_upper" or level == "state_lower" \ or level == "state": parent_location = "location" if district: add_district = '-[:ENCOMPASSES]->' \ '(location:Location ' \ '{name: "%s", sector: "%s"})' \ '' % (district, level) parent_location = "b" # use sector for level input since we're talking about # state_upper and state_lower with the position # and level input here only has state, federal, and local loc_query = '(a:Location {name: "United States of America"})' \ '-[:ENCOMPASSES]->' \ '(%s:Location {name: "%s"})%s' % ( parent_location, location, add_district) else: loc_query = '(location:Location {external_id:"%s"})' % location query = 'MATCH %s-' \ '[:POSITIONS_AVAILABLE]->(position:Position ' \ '{name:"%s", level:"%s"}) RETURN position' % \ (loc_query, focused_on, level) res, _ = db.cypher_query(query) if not res.one: focused_on = slugify(focused_on).title().replace('-', ' ')\ .replace('_', ' ') new_position = Position(verified=False, name=focused_on, level=level, user_created=True).save() query = 'MATCH %s, ' \ '(position:Position {object_uuid:"%s"}) ' \ 'CREATE UNIQUE (position)' \ '<-[r:POSITIONS_AVAILABLE]-(location) ' \ 'RETURN position' % (loc_query, new_position.object_uuid) res, _ = db.cypher_query(query) query = 'MATCH %s-' \ '[:POSITIONS_AVAILABLE]->' \ '(position:Position {name: "%s", level: "%s"}),' \ '(mission:Mission {object_uuid: "%s"}),' \ '(quest:Quest {owner_username: "******"}) ' \ 'CREATE UNIQUE (position)<-[:FOCUSED_ON]-' \ '(mission)<-[:EMBARKS_ON]-(quest) ' \ 'WITH quest, location, mission, position ' \ 'CREATE UNIQUE (location)<-[:WITHIN]-(mission) ' \ 'RETURN mission' % ( loc_query, focused_on, level, mission.object_uuid, owner_username) res, _ = db.cypher_query(query) mission = Mission.inflate(res.one) elif focus_type == "advocacy": focused_on = slugify(focused_on) try: Tag.nodes.get(name=focused_on) except (DoesNotExist, Tag.DoesNotExist): Tag(name=focused_on).save() if level == "local": loc_query = '(location:Location {external_id: "%s"}) ' % ( location) elif level == "state": if district: loc_query = '(:Location {name: ' \ '"United States of America"})' \ '-[:ENCOMPASSES]->(:Location {name: "%s"})' \ '-[:ENCOMPASSES]->(location:Location ' \ '{name: "%s", sector: "federal"}) ' % ( location, district) else: loc_query = '(:Location {name: ' \ '"United States of America"})' \ '-[:ENCOMPASSES]->' \ '(location:Location {name: "%s"}) ' % location elif level == "federal": if district: loc_query = '(:Location {name: ' \ '"United States of America"})' \ '-[:ENCOMPASSES]->(:Location {name: "%s"})' \ '-[:ENCOMPASSES]->(location:Location ' \ '{name: "%s", sector: "federal"}) ' % ( location, district) elif location and focused_on != "President": loc_query = '(:Location {name: ' \ '"United States of America"})' \ '-[:ENCOMPASSES]->' \ '(location:Location {name: "%s"}) ' % location else: loc_query = '(location:Location {name: ' \ '"United States of America"}) ' else: raise serializers.ValidationError( {"detail": "Sorry Could Not Determine Where You're " "advocating. Please try a different " "location or contact us.", "developer_message": "", "status_code": status.HTTP_400_BAD_REQUEST}) query = 'MATCH (tag:Tag {name: "%s"}), ' \ '(quest:Quest {owner_username: "******"}), ' \ '(mission:Mission {object_uuid: "%s"}), ' \ '%s WITH tag, quest, mission, location ' \ 'CREATE UNIQUE (tag)<-[:FOCUSED_ON]-(mission)' \ '<-[:EMBARKS_ON]-(quest) WITH location, mission ' \ 'CREATE UNIQUE (mission)-[:WITHIN]->(location) ' \ 'RETURN mission' % (focused_on, owner_username, mission.object_uuid, loc_query) res, _ = db.cypher_query(query) if res.one is not None: mission = Mission.inflate(res.one) setup_onboarding(quest, mission) spawn_task(task_func=send_reengage_message, task_param={"mission_uuid": mission.object_uuid, "mission_type": focus_type}, countdown=900) return mission
def object_vote_notifications(object_uuid, previous_vote_type, new_vote_type, voting_pleb): sb_object = get_parent_votable_content(object_uuid) try: current_pleb = Pleb.get(username=voting_pleb) except (DoesNotExist, Pleb.DoesNotExist, CypherException, ClientError, IOError) as e: raise object_vote_notifications.retry(exc=e, countdown=10, max_retries=None) if new_vote_type != 2 and previous_vote_type != new_vote_type: reputation_change = sb_object.down_vote_adjustment modifier = "downvoted" reputation_message = "" if new_vote_type: reputation_change = sb_object.up_vote_adjustment modifier = "upvoted" if reputation_change: # using b tag here because a div or p will break the rendering of # the notification html due to them not being allowed in a tags color = "sb_reputation_notification_change_red" if reputation_change > 0: color = "sb_reputation_notification_change_green" reputation_message = render_to_string( 'notification_message.html', {'color': color, 'reputation_change': "%+d" % reputation_change}) if sb_object.visibility != "public": reputation_message = "" public = False action_name = " %s %s %s " % ("%s your" % modifier, sb_object.get_child_label(), reputation_message) titled_content = get_parent_titled_content(sb_object.object_uuid) if not isinstance(titled_content, Exception): truncate_content = titled_content.title else: truncate_content = sb_object.content if sb_object.visibility == "public": action_name = '%s from vote on "%s"' % (reputation_message, smart_truncate( truncate_content)) public = True if previous_vote_type != new_vote_type and new_vote_type != 2: if sb_object.get_child_label().lower() == "comment": comment_on = Comment.get_comment_on(sb_object.object_uuid) page_type = comment_on.get_child_label().lower() object_id = comment_on.object_uuid else: page_type = sb_object.get_child_label().lower() object_id = sb_object.object_uuid res = spawn_task(spawn_notifications, task_param={ 'from_pleb': current_pleb.username, 'to_plebs': [sb_object.owner_username], 'sb_object': sb_object.object_uuid, 'notification_id': str(uuid1()), 'url': reverse( "single_%s_page" % page_type, kwargs={"object_uuid": object_id}), 'action_name': action_name, 'public': public }) if isinstance(res, Exception): raise object_vote_notifications.retry(exc=res, countdown=10, max_retries=None) return True