Example #1
0
class person(StructuredNode):
    id = IntegerProperty(unique_index=True)

    # traverse outgoing IS_FROM relations, inflate to Country objects
    following_p = RelationshipTo('person', 'FOLLOW')
    followed_p = RelationshipFrom('person', 'FOLLOW')
Example #2
0
class PersonNode(StructuredNode):
    name = StringProperty()
    mobile = StringProperty()
    apartment = RelationshipTo(ApartmentNode, 'LIVES_IN')
Example #3
0
class Supplier(StructuredNode):
    name = StringProperty()
    delivery_cost = IntegerProperty()
    coffees = RelationshipTo('Coffee',
                             'COFFEE SUPPLIERS')  # Space to check for escaping
Example #4
0
class District(StructuredNode):
    name = StringProperty(unique_index=True)
    city = RelationshipTo(City, "DistrictCityRel")
Example #5
0
class BuildingNode(StructuredNode):
    address = StringProperty(unique_index=True)
    neighborhood = RelationshipTo('NeighborhoodNode', 'PART_OF')
    apartments = RelationshipFrom('ApartmentNode', 'PART_OF')
Example #6
0
class App(StructuredNode):
    app_id = UniqueIdProperty()
    name = StringProperty()

    tags = RelationshipTo(Tag, 'TAGGED', model=AppTagRel)
Example #7
0
class Vehicle(StructuredNode):
    code = StringProperty(required=True, unique_index=True)
    color = StringProperty(default="000000")
    description = StringProperty()

    to = RelationshipTo('Station', 'TO', model=FrTo)
Example #8
0
class Track(SmallTrack):
    '''
    Represents a Track on Spotify
    '''
    album = RelationshipTo('model.graph.spotify.album.Album', 'FROM')
    artists = RelationshipTo('model.graph.spotify.artist.Artist', 'BY')
    playlists = RelationshipTo('model.graph.spotify.playlist.Playlist',
                               'FEATURED IN')

    # billboard_data = RelationshipTo('model.graph.billboard.track.Track', 'RANKED AS')
    genius_data = RelationshipTo('model.graph.genius.track.Track',
                                 'ON GENIUS AS')

    available_markets = ArrayProperty()
    disc_number = IntegerProperty()
    duration_ms = IntegerProperty()
    explicit = BooleanProperty()
    external_ids = JSONProperty()
    external_urls = ArrayProperty()
    href = StringProperty()
    is_local = BooleanProperty()
    preview_url = StringProperty()
    track_number = IntegerProperty()
    type = StringProperty()

    # We can worry about analysis at a later point
    analysis = JSONProperty()

    # Features
    key = IntegerProperty()
    mode = IntegerProperty()
    time_signature = IntegerProperty()
    acousticness = FloatProperty()
    danceability = FloatProperty()
    energy = FloatProperty()
    instrumentalness = FloatProperty()
    liveness = FloatProperty()
    loudness = FloatProperty()
    speechiness = FloatProperty()
    valence = FloatProperty()
    tempo = FloatProperty()
    analysis_url = StringProperty()
    popularity = IntegerProperty()

    @classmethod
    @db.transaction
    def add_genius(cls, uri, data):
        '''
        Updates a node to add Genius data

        :param uri: the Spotify URI of the track
        :param data: the genius data
        :return: the updated node
        '''
        track = cls.nodes.get_or_none(uri=uri)
        if track:
            track.genius_data = data
            track.save()
        return track

    @classmethod
    def add_zVector(cls, uri, data: List[List[float]]):
        '''
        Adds zVector data to the track

        :param uri: the Spotify URI of the track
        :param data: the zVector data as a list of lists, not a numpy array
        :return: the updated node
        '''
        # print(uri)
        db.set_connection(connection_url())
        # query = 'MATCH (n: Track {uri: "%s"}) RETURN n LIMIT 1' % (uri)
        # results, meta = db.cypher_query(query=query)
        # track = [cls.inflate(row[0]) for row in results]
        #
        # if track:
        #     track = track[0]
        # print(track.name)
        # print('Please save', track)

        # f**k neomodel ffs
        data = json.dumps({'zVector': data})

        query = '''
            MATCH (t:Track {uri:'%s'})
            WITH t, properties(t) as snapshot
            SET t.zVector = '%s'
            RETURN snapshot
            ''' % (uri, data)
        # print(query)
        track = db.cypher_query(query)
        return track

    def get_song_features(self, as_list=False):
        '''
        Gets the song features as a dictionary

        :param as_list: whether to return a list or dictionary
        :return: the song features
        '''
        cols = [
            'key', 'mode', 'time_signature', 'acousticness', 'danceability',
            'energy', 'instrumentalness', 'liveness', 'loudness',
            'speechiness', 'valence', 'tempo', 'popularity'
        ]
        tor = self.get_features(cols)
        for key, val in tor.items():
            if val is None:
                tor[key] = 0
        if as_list:
            return [tor[a] for a in cols]
        return tor

    @classmethod
    def get_songs_in_playlists(cls, limit, offset=0):
        '''
        Gets only songs that appear in playlists

        :return: the query to do that
        '''
        query = '''
            MATCH (t: Track)-[r:`FEATURED IN`]->(p: Playlist)
            WITH t, count(r) as playlist_count
            WHERE playlist_count > 0
            RETURN t
            '''
        return cls.paginate(limit, offset, query)

    @classmethod
    def get_songs_not_in_playlists(cls, limit, offset=0):
        '''
        Gets only songs that appear in playlists

        :return: the query to do that
        '''
        query = '''
                MATCH (t: Track) WHERE NOT EXISTS (t.zVector) RETURN t
                '''
        return cls.paginate(limit, offset, query)
Example #9
0
class Book(StructuredNode):
    title = StringProperty(unique_index=True)
    author = RelationshipTo('Author', 'AUTHOR')
Example #10
0
class Function(StructuredNode):
    name = StringProperty(required=True)
    decompilation = StringProperty()
    imports_symbol = RelationshipTo('Symbol', 'imports')
    defined_at = RelationshipFrom('File', 'defines')
Example #11
0
class Dog(StructuredNode):
    name = StringProperty(required=True)
    owner = RelationshipTo('Person', 'owner')
Example #12
0
class File(StructuredNode):
    name = StringProperty(unique_index=True)
    path = StringProperty()
    hash = StringProperty()
    uses = RelationshipTo('Symbol', 'uses')
    provides = RelationshipTo('Symbol', 'provides')
Example #13
0
class Pleb(Searchable):
    """
    Signals and overwritting the save method don't seem to have any affect
    currently. We'll want to look into this and instead of having cache
    methods sprinkled around the code, overwrite get/save methods to first
    check the cache for the id of the object.
    Should also be updating/destroying the document in the search index upon
    save/update/destroy
    """
    search_modifiers = {
        'post': 10, 'comment_on': 5, 'upvote': 3, 'downvote': -3,
        'time': -1, 'proximity_to_you': 10, 'proximity_to_interest': 10,
        'share': 7, 'flag_as_inappropriate': -5, 'flag_as_spam': -100,
        'flag_as_other': -10, 'solution': 50, 'starred': 150, 'seen_search': 5,
        'seen_page': 20
    }
    gender = StringProperty()
    oauth_token = StringProperty()
    username = StringProperty(unique_index=True)
    first_name = StringProperty()
    last_name = StringProperty()
    middle_name = StringProperty()
    # Just an index as some individuals share email addresses still
    email = StringProperty(index=True)
    date_of_birth = DateTimeProperty()
    primary_phone = StringProperty()
    secondary_phone = StringProperty()
    profile_pic = StringProperty(default=get_default_profile_pic)
    wallpaper_pic = StringProperty(default=get_default_wallpaper_pic)
    reputation = IntegerProperty(default=0)
    is_rep = BooleanProperty(default=False)
    is_admin = BooleanProperty(default=False)
    is_sage = BooleanProperty(default=False)
    is_verified = BooleanProperty(default=True)
    search_index = StringProperty()
    reputation_update_seen = BooleanProperty(default=True)
    # Placeholders that enable us to gather a user's employer and
    # occupation if they are donating to a political campaign mission
    # We'll eventually be transitioning these to a node of their own.
    employer_name = StringProperty()
    occupation_name = StringProperty()
    # base_index_id is the plebs id in the base elasticsearch index
    base_index_id = StringProperty()
    email_verified = BooleanProperty(default=False)
    populated_personal_index = BooleanProperty(default=False)
    initial_verification_email_sent = BooleanProperty(default=False)

    stripe_customer_id = StringProperty()
    # The credit card associated with the customer
    stripe_default_card_id = StringProperty()
    # last_counted_vote_node is the node we want to query on to get
    # reputation change over time
    last_counted_vote_node = StringProperty(default=None)
    # vote_from_last_refresh is what gets stored every time a user
    # refreshes their page, allows us to easily swap it with
    # last_counted_vote_node when they check their reputation
    vote_from_last_refresh = StringProperty(default=None)
    mission_signup = StringProperty(default=None)

    # Relationships
    privileges = RelationshipTo('sb_privileges.neo_models.Privilege', 'HAS',
                                model=ActionActiveRel)
    actions = RelationshipTo('sb_privileges.neo_models.SBAction', 'CAN',
                             model=ActionActiveRel)
    restrictions = RelationshipTo('sb_privileges.neo_models.Restriction',
                                  'RESTRICTED_BY', model=RestrictionRel)
    badges = RelationshipTo("sb_badges.neo_models.Badge", "BADGES")
    oauth = RelationshipTo("plebs.neo_models.OauthUser", "OAUTH_CLIENT")
    tags = RelationshipTo('sb_tags.neo_models.Tag', 'TAGS',
                          model=TagRelationship)
    voted_on = RelationshipTo('sb_base.neo_models.VotableContent', 'VOTES')
    viewed = RelationshipTo('sb_search.neo_models.Searchable', "VIEWED",
                            model=Impression)
    interests = RelationshipTo("sb_tags.neo_models.Tag", "INTERESTED_IN")
    friends = RelationshipTo("Pleb", "FRIENDS_WITH", model=FriendRelationship)
    # Optimization
    wall = RelationshipTo('sb_wall.neo_models.Wall', 'OWNS_WALL')
    friend_requests_sent = RelationshipTo(
        "plebs.neo_models.FriendRequest", 'SENT_A_REQUEST')
    friend_requests_received = RelationshipTo(
        "plebs.neo_models.FriendRequest", 'RECEIVED_A_REQUEST')
    user_weight = RelationshipTo('Pleb', 'WEIGHTED_USER',
                                 model=UserWeightRelationship)
    object_weight = RelationshipTo(
        'sb_base.neo_models.SBContent', 'OBJECT_WEIGHT',
        model=RelationshipWeight)
    searches = RelationshipTo('sb_search.neo_models.SearchQuery', 'SEARCHED',
                              model=SearchCount)
    clicked_results = RelationshipTo('sb_search.neo_models.SearchResult',
                                     'CLICKED_RESULT')
    official = RelationshipTo('sb_public_official.neo_models.PublicOfficial',
                              'IS_AUTHORIZED_AS', model=OfficialRelationship)
    # TODO our queries might not need HAS_SENATOR or HAS_HOUSE_REPRESENTATIVE
    # this distinction is covered by our endpoints of senators/house
    # representatives. We can change the relationship to REPRESENTED_BY
    # and utilize the Senate/House Representative/etc label to get the proper
    # official. This would require a Senator label though and not sure how we
    # want to handle this in a scalable way where we don't have to make new
    # relationships and classes for every new type of rep. Could potentially
    # define a few and then use a general class with an attribute that inherits
    # from them. Or we could start adding Labels that aren't associated with
    # classes based on the type of rep. This would allow us to use the same
    # types of queries and easily get all the types of representatives.
    senators = RelationshipTo('sb_public_official.neo_models.PublicOfficial',
                              'HAS_SENATOR')
    house_rep = RelationshipTo('sb_public_official.neo_models.PublicOfficial',
                               'HAS_HOUSE_REPRESENTATIVE')
    president = RelationshipTo('sb_public_official.neo_models.PublicOfficial',
                               'HAS_PRESIDENT')
    flags = RelationshipTo('sb_flags.neo_models.Flag', "FLAGS")
    beta_user = RelationshipTo('plebs.neo_models.BetaUser', "BETA_USER")
    url_content = RelationshipTo('sb_uploads.neo_models.URLContent',
                                 'URL_CONTENT')
    address = RelationshipTo("sb_address.neo_models.Address", 'LIVES_AT')

    # Users can only have one campaign as the campaign is essentially their
    # action page and account information. They won't be able to create
    # multiple accounts or multiple action pages. We can then utilize the
    # campaign as another type of wall where they associate Projects or other
    # things to. If a user is waging a `PoliticalCampaign` their Action page
    # changes a little and they start being able to receive pledged votes and
    # there are more limitations on how donations occur.

    # Quest
    # Access if this Pleb is waging a Quest
    # Neomodel: quest Cypher IS_WAGING
    # RelationshipFrom('sb_quests.neo_models.Quest')

    # Edits
    # Access if this Pleb can edit a Quest through:
    # Neomodel: editors Cypher: EDITOR_OF
    # RelationshipTo('sb_quests.neo_models.Quest')

    # Moderator
    # Access if this Pleb can view financial data of a Quest through:
    # Neomodel: moderators Cypher: MODERATOR_OF
    # RelationshipTo('sb_quests.neo_models.Quest')

    # Volunteer
    # Access what this Pleb has volunteered to do through:
    # Neomodel: volunteer Cypher: WANTS_TO
    # RelationshipFrom('sb_volunteers.neo_models.Volunteer')

    # Use stripe_account on quest instead
    stripe_account = StringProperty()
    # Can this just be a vote? Have it set like we do with votable content
    # with the assumption we can
    # utilize a different serializer that only enables up/off votes rather than
    # also allowing down votes to be cast. Then we can utilize the different
    # relationship to track any special items.
    donations = RelationshipTo('sb_donations.neo_models.Donation',
                               'DONATIONS_GIVEN')
    following = RelationshipTo('plebs.neo_models.Pleb', 'FOLLOWING',
                               model=FollowRelationship)
    party_affiliations = RelationshipTo('plebs.neo_models.PoliticalParty',
                                        'AFFILIATES_WITH')
    activity_interests = RelationshipTo('plebs.neo_models.ActivityInterest',
                                        'WILL_PARTICIPATE')

    @property
    def customer_token(self):
        # DO NOT USE: NON-USE PLACEHOLDER FOR SERIALIZER
        return None

    @classmethod
    def get(cls, username, cache_buster=False):
        profile = None
        if username is None:
            return None
        if cache_buster is False:
            profile = cache.get(username)
        if profile is None or cache_buster:
            res, _ = db.cypher_query(
                "MATCH (a:%s {username:'******'}) RETURN a" % (
                    cls.__name__, username))
            if res.one:
                res.one.pull()
                profile = cls.inflate(res.one)
            else:
                raise DoesNotExist('Profile with username: %s '
                                   'does not exist' % username)
            cache.set(username, profile)
        return profile

    @classmethod
    def clear_unseen_friend_requests(cls, username):
        """
        This method sets all the existing friend requests a given Pleb has
        to seen. The method doesn't return anything because if the query fails
        it will throw a Cypher Exception which will be caught and handled by
        a view. Please wrap this function with the proper handler if you are
        calling it in a task.

        Limitations:
        This method requires that a username be passed rather than being
        executed on an initialized Pleb.

        Made this into a class method rather than a method that could be used
        on an initialized Pleb for optimization. Instead of querying a Pleb
        then having to execute this same query utilizing self.username it is
        more efficient to utilize a defined username that we can retrieve
        from something like request.user.username without having to get the
        Pleb. If there is want to transition this to a non-classmethod we
        could utilize the cache to get the initial Pleb and then call
        it based on that but that still runs the chance of executing two
        queries.

        :param username:
        :return:
        """
        value = get_current_time().astimezone(pytz.utc)
        epoch_date = datetime(1970, 1, 1, tzinfo=pytz.utc)
        time_seen = float((value - epoch_date).total_seconds())
        query = 'MATCH (a:Pleb {username: "******"})-[:RECEIVED_A_REQUEST]->' \
                '(n:FriendRequest) WHERE n.seen=False' \
                ' SET n.seen = True, ' \
                'n.time_seen = %s' % (username, time_seen)
        db.cypher_query(query)

    @classmethod
    def get_mission_political_donations(cls, username, mission_id):
        donation_amount = cache.get('%s_%s_donation_amount' % (username,
                                                               mission_id))
        beg_year = datetime(datetime.now(pytz.utc).year, 1, 1).strftime("%s")
        end_year = datetime(datetime.now(pytz.utc).year + 1, 1, 1
                            ).strftime("%s")
        if donation_amount == 0 or donation_amount is None:
            query = 'MATCH (p:Pleb {username: "******"})-[:DONATIONS_GIVEN]->' \
                    '(d:Donation)-[:DONATED_TO]->' \
                    '(c:Mission {object_uuid:"%s", ' \
                    'focus_on_type: "position"}) ' \
                    'WHERE d.created > %s AND d.created < %s ' \
                    'RETURN sum(d.amount)' \
                    % (username, mission_id, beg_year, end_year)
            res, col = db.cypher_query(query)
            donation_amount = res.one if res.one is not None else 0
            cache.set('%s_%s_donation_amount' %
                      (username, mission_id), donation_amount)
        return donation_amount

    def get_quest(self):
        query = 'MATCH (p:Pleb {username: "******"})-[:IS_WAGING]->(c:Quest) ' \
                'RETURN c.owner_username' % self.username
        res, _ = db.cypher_query(query)
        return res.one

    def get_official_phone(self):
        query = 'MATCH (p:Pleb {username:"******"})-[:IS_AUTHORIZED_AS]->' \
                '(o:PublicOfficial) RETURN o.gov_phone' % self.username
        res, _ = db.cypher_query(query)
        return res.one

    def deactivate(self):
        pass

    def get_address(self):
        query = 'MATCH (p:Pleb {username: "******"})-[:LIVES_AT]->(a:Address) ' \
                'RETURN a' % self.username
        res, _ = db.cypher_query(query)
        try:
            return Address.inflate(res.one)
        except AttributeError:
            return None

    def get_actions(self, cache_buster=False):
        actions = cache.get("%s_actions" % self.username)
        if actions is None or cache_buster is True:
            query = 'MATCH (a:Pleb {username: "******"})-' \
                    '[:CAN {active: true}]->(n:`SBAction`) ' \
                    'RETURN n.resource' % self.username
            res, col = db.cypher_query(query)
            actions = [row[0] for row in res]
            cache.set("%s_actions" % self.username, actions)
        return actions

    def get_privileges(self, cache_buster=False):
        privileges = cache.get("%s_privileges" % self.username)
        if privileges is None or cache_buster is True:
            query = 'MATCH (a:Pleb {username: "******"})-' \
                    '[:HAS {active: true}]->(n:`Privilege`) ' \
                    'RETURN n.name' % self.username
            res, col = db.cypher_query(query)
            privileges = [row[0] for row in res]
            cache.set("%s_privileges" % self.username, privileges)
        return privileges

    def get_badges(self):
        return self.badges.all()

    def get_full_name(self):
        return str(self.first_name) + " " + str(self.last_name)

    def update_quest(self):
        query = 'MATCH (p:Pleb {username:"******"})-[:IS_WAGING]->' \
                '(c:Quest) SET c.first_name="%s", c.last_name="%s"' % \
                (self.username, self.first_name, self.last_name)
        res, _ = db.cypher_query(query)
        return True

    def update_weight_relationship(self, sb_object, modifier_type):
        rel = self.object_weight.relationship(sb_object)
        if modifier_type in self.search_modifiers.keys():
            rel.weight += self.search_modifiers[modifier_type]
            rel.status = modifier_type
            rel.save()
            return rel.weight

    def get_votable_content(self):
        from sb_base.neo_models import VotableContent
        query = 'MATCH (a:Pleb {username: "******"})<-[:OWNED_BY]-(' \
                'b:VotableContent) WHERE b.visibility = "public" RETURN b' \
                '' % self.username
        res, col = db.cypher_query(query)

        return [VotableContent.inflate(row[0]) for row in res]

    def get_total_rep(self):
        rep_list = []
        base_tags = {}
        tags = {}
        original_rep = self.reputation
        total_rep = 0
        for item in self.get_votable_content():
            rep_res = item.get_rep_breakout()
            if isinstance(rep_res, Exception) is True:
                return rep_res
            total_rep += rep_res['total_rep']
            if 'base_tag_list' in rep_res.keys():
                for base_tag in rep_res['base_tag_list']:
                    base_tags[base_tag] = rep_res['rep_per_tag']
                for tag in rep_res['tag_list']:
                    tags[tag] = rep_res['rep_per_tag']
            rep_list.append(rep_res)
        if total_rep < 0:
            total_rep = 0
        self.reputation = total_rep
        self.save()
        cache.delete(self.username)
        return {"rep_list": rep_list,
                "base_tags": base_tags,
                "tags": tags,
                "total_rep": total_rep,
                "previous_rep": original_rep}

    def get_object_rep_count(self):
        pass

    def get_available_flags(self):
        pass

    def vote_on_content(self, content):
        pass

    def get_question_count(self):
        query = 'MATCH (pleb:Pleb {username:"******"})<-[:OWNED_BY]-' \
                '(question:Question) RETURN COUNT(question)' % self.username
        res, _ = db.cypher_query(query)
        return res.one

    def get_solution_count(self):
        query = 'MATCH (pleb:Pleb {username:"******"})<-[:OWNED_BY]-' \
                '(solution:Solution) RETURN COUNT(solution)' % self.username
        res, _ = db.cypher_query(query)
        return res.one

    def get_post_count(self):
        query = 'MATCH (pleb:Pleb {username:"******"})<-[:OWNED_BY]-' \
                '(post:Post) RETURN COUNT(post)' % self.username
        res, _ = db.cypher_query(query)
        return res.one

    def get_comment_count(self):
        query = 'MATCH (pleb:Pleb {username:"******"})<-[:OWNED_BY]-' \
                '(comment:Comment) RETURN COUNT(comment)' % self.username
        res, _ = db.cypher_query(query)
        return res.one

    def get_friends(self):
        return self.friends.all()

    def is_friends_with(self, username):
        query = "MATCH (a:Pleb {username:'******'})-" \
                "[friend:FRIENDS_WITH]->(b:Pleb {username:'******'}) " \
                "RETURN friend.active" % (self.username, username)
        res, col = db.cypher_query(query)
        if len(res) == 0:
            return False
        try:
            return res[0][0]
        except IndexError:
            return False

    def get_wall(self):
        """
        Cypher Exception and IOError excluded on purpose, please do not add.
        The functions calling this expect the exceptions to be thrown and
        handle the exceptions on their own if they end up occurring.
        :return:
        """
        from sb_wall.neo_models import Wall
        wall = cache.get("%s_wall" % self.username)
        if wall is None:
            query = "MATCH (a:Pleb {username:'******'})-" \
                    "[:OWNS_WALL]->(b:Wall) RETURN b" % self.username
            res, col = db.cypher_query(query)
            try:
                wall = Wall.inflate(res[0][0])
                cache.set("%s_wall" % self.username, wall)
            except IndexError:
                # This may not be needed as the only way to get here is if
                # the wall was removed from the user or never created in the
                # first place. Since our tasks should never complete until a
                # wall has been created we shouldn't run into this. But to be
                # safe we've added it in. If we do manage to get here though
                # we may want to think about recovery methods or alerts we
                # should be sending out.
                return None
        return wall

    def determine_reps(self):
        from sb_public_official.utils import determine_reps
        return determine_reps(self)

    def get_donations(self):
        query = 'MATCH (p:Pleb {username: "******"})-[:DONATIONS_GIVEN]->' \
                '(d:Donation)-[:CONTRIBUTED_TO]->(mission:Mission) ' \
                'RETURN d.object_uuid' % self.username
        res, col = db.cypher_query(query)
        return [row[0] for row in res]

    def get_sagebrew_donations(self):
        query = 'MATCH (p:`Pleb` {username: "******"})-[:DONATIONS_GIVEN]->' \
                '(d:`Donation`) WHERE NOT (d)-[:CONTRIBUTED_TO]->(:Mission) ' \
                'AND NOT (d)-[:CONTRIBUTED_TO]->(:Quest) ' \
                'RETURN d.object_uuid' % self.username
        res, col = db.cypher_query(query)
        return [row[0] for row in res]

    def is_authorized_as(self):
        from sb_public_official.neo_models import PublicOfficial
        official = cache.get("%s_official" % self.username)
        if official is None:
            query = 'MATCH (p:Pleb {username: "******"})-[r:IS_AUTHORIZED_AS]->' \
                    '(o:PublicOfficial) WHERE r.active=true RETURN o' \
                    % self.username
            res, _ = db.cypher_query(query)
            try:
                official = PublicOfficial.inflate(res[0][0])
                cache.set("%s_official" % self.username, official)
            except IndexError:
                official = None
        return official

    def is_following(self, username):
        query = 'MATCH (p:Pleb {username:"******"})<-[r:FOLLOWING]-' \
                '(p2:Pleb {username:"******"}) RETURN r.active' % \
                (self.username, username)
        res, _ = db.cypher_query(query)
        return res.one

    def follow(self, username):
        """
        The username passed to this function is the user who will be following
        the user the method is called upon.
        This method is not idempotent on it's own. You must first call
        is_following to ensure the relationship doesn't already exist.
        :param username:
        """
        query = 'MATCH (p:Pleb {username:"******"}), (p2:Pleb {username:"******"}) ' \
                'WITH p, p2 CREATE UNIQUE (p)<-[r:FOLLOWING]-(p2) SET ' \
                'r.active=true RETURN r.active' % (self.username, username)
        res, _ = db.cypher_query(query)
        return res.one

    def unfollow(self, username):
        """
        The username passed to this function is the user who will stop
        following the user the method is called upon.
        :param username:
        """
        query = 'MATCH (p:Pleb {username:"******"})<-[r:FOLLOWING]-(p2:Pleb ' \
                '{username:"******"}) SET r.active=false RETURN r.active' \
                % (self.username, username)
        res, _ = db.cypher_query(query)
        return res.one

    @property
    def reputation_change(self):
        # See create_vote_node task in sb_votes tasks for where this is deleted
        res = cache.get("%s_reputation_change" % self.username)
        if res is None:
            # last_counted_vote_node is set in sb_vote/tasks if it is None.
            query = 'MATCH (last_counted:Vote {object_uuid:"%s"})-' \
                    '[:CREATED_ON]->(s:Second) WITH s, last_counted MATCH ' \
                    '(s)-[:NEXT*]->(s2:Second)<-[:CREATED_ON]-(v:Vote)<-' \
                    '[:LAST_VOTES]-(content:VotableContent)-[:OWNED_BY]->' \
                    '(p:Pleb {username:"******"}) WITH v ORDER BY v.created DESC ' \
                    'RETURN sum(v.reputation_change) ' \
                    'as rep_change, collect(v.object_uuid)[0] as last_created' \
                    % (self.last_counted_vote_node, self.username)
            res, _ = db.cypher_query(query)
            if not res:
                return 0
            # Have to cast to dict because pickle cannot handle the object
            # returned from cypher_query
            res = res[0].__dict__
            cache.set("%s_reputation_change" % self.username, res)
        reputation_change = res['rep_change']
        last_seen = res['last_created']
        if last_seen != self.vote_from_last_refresh:
            self.vote_from_last_refresh = res['last_created']
            self.save()
            cache.delete(self.username)
        if reputation_change >= 1000 or reputation_change <= -1000:
            return "%dk" % (int(reputation_change / 1000.0))
        return reputation_change

    def get_political_parties(self):
        query = "MATCH (a:Pleb {username:'******'})-[:AFFILIATES_WITH]->" \
                "(b:PoliticalParty) RETURN b.name" % self.username
        res, _ = db.cypher_query(query)
        return [row[0] for row in res]

    def get_activity_interests(self):
        query = "MATCH (a:Pleb {username:'******'})-[:WILL_PARTICIPATE]->" \
                "(b:ActivityInterest) RETURN b.name" % self.username
        res, _ = db.cypher_query(query)
        return [row[0] for row in res]

    """
class Subject(StructuredNode):
    subject_name = StringProperty(unique_index=True)
    DBpediaURL = StringProperty()
    predicate = RelationshipTo(Object, 'predicate', model=RelationshipModel)
Example #15
0
class PublicOfficial(Searchable):
    """
    The PublicOfficial does not inherit from Pleb as Plebs must be associated
    with a user. PublicOfficial is a node that is dynamically populated based
    on our integrations with external services. It cannot be modified by
    users of the web app. Plebs can be attached to a PublicOfficial though
    if they are that individual. Public Officials should also always be
    available whether or not a user exits or joins the system so that we can
    always make the public information known and populate action areas
    for officials that are not yet signed up.
    """
    first_name = StringProperty()
    last_name = StringProperty()
    middle_name = StringProperty()
    gender = StringProperty()
    date_of_birth = DateTimeProperty()
    gt_id = StringProperty(index=True)
    title = StringProperty()
    bio = StringProperty(default="")
    name_mod = StringProperty()
    current = BooleanProperty()
    district = IntegerProperty(default=0)
    state = StringProperty()
    website = StringProperty()
    start_date = DateTimeProperty()
    end_date = DateTimeProperty()
    full_name = StringProperty()
    gov_phone = StringProperty()
    # recipient_id and customer_id are stripe specific attributes
    recipient_id = StringProperty()
    customer_id = StringProperty()
    terms = IntegerProperty()
    twitter = StringProperty()
    youtube = StringProperty()
    bioguideid = StringProperty(unique_index=True)
    state_district = StringProperty()
    state_chamber = StringProperty()
    # address and contact form are gained from the term data and they will be
    # updated to their current office address and their current contact form
    address = StringProperty()
    contact_form = StringProperty()
    # bioguide is used to get the reps public profile picture

    # relationships
    pleb = RelationshipTo('plebs.neo_models.Pleb', 'AUTHORIZED_AS')
    # sponsored = RelationshipTo('sb_public_official.neo_models.Bill',
    #                            "SPONSORED")
    # co_sponsored = RelationshipTo('sb_public_official.neo_models.Bill',
    #                               "COSPONSORED")
    # proposed = RelationshipTo('sb_public_official.neo_models.Bill',
    #                           "PROPOSED")
    # hearings = RelationshipTo('sb_public_official.neo_models.Hearing',
    #                           "ATTENDED")
    # experience = RelationshipTo('sb_public_official.neo_models.Experience',
    #                             "EXPERIENCED")
    gt_person = RelationshipTo('govtrack.neo_models.GTPerson', 'GTPERSON')
    gt_role = RelationshipTo('govtrack.neo_models.GTRole', 'GTROLE')
    # the current term is also included in the number of terms under the term
    # relationship, the current_term relationship is a shortcut for us to
    # access the term that the official is currently in
    term = RelationshipTo('govtrack.neo_models.Term', 'SERVED_TERM')
    current_term = RelationshipTo('govtrack.neo_models.Term', 'CURRENT_TERM')
    quest = RelationshipTo('sb_quests.neo_models.Quest', 'IS_HOLDING')

    def get_quest(self):
        from sb_quests.neo_models import Quest
        # DEPRECATED use get_mission or get_quest instead
        # Not adding a deprecation warning as we cover this with the migration
        # command. Once that is executed we'll need to fix or remove this
        query = 'MATCH (o:PublicOfficial {object_uuid:"%s"})-' \
                '[:IS_HOLDING]->(c:Quest) RETURN c' \
                % self.object_uuid
        res, _ = db.cypher_query(query)
        if res.one:
            return Quest.inflate(res.one)
        else:
            return None
Example #16
0
class Location(SBObject):
    name = StringProperty(index=True)
    # Valid Sectors:
    #     state_upper - State Senator Districts
    #     state_lower - State House Representative Districts
    #     federal - U.S. Federal Districts (House of Reps)
    #     local - Everything else :)
    sector = StringProperty(default=None)
    geo_data = StringProperty(default=None)

    encompasses = RelationshipTo('sb_locations.neo_models.Location',
                                 'ENCOMPASSES')
    encompassed_by = RelationshipTo('sb_locations.neo_models.Location',
                                    'ENCOMPASSED_BY')
    # Questions
    # Access Questions that are related to this location through:
    # Neomodel: focus_location Cypher: FOCUSED_ON

    # Mission
    # Access Missions that are related to this location through:
    # Neomodel: location Cypher: WITHIN

    # optimizations
    # TODO these might be best moved to the Question or maybe lat, long to since
    # we only need to create the marker on the display page
    # Allows us to determine which service to query with the id for additional
    # info
    # valid values: smarty_streets, google_maps
    created_by = StringProperty(default="smarty_streets")
    # ID provided by a third party representing the ID that should be used
    # when querying their service.
    external_id = StringProperty(default=None, index=True)

    @classmethod
    def get_encompasses(cls, object_uuid):
        query = 'MATCH (n:`Location` {object_uuid: "%s"})-' \
                '[:ENCOMPASSES]->(e:`Location`) RETURN e.object_uuid' % (
                    object_uuid)
        res, _ = db.cypher_query(query)
        return [row[0] for row in res]

    @classmethod
    def get_encompassed_by(cls, object_uuid):
        query = 'MATCH (n:`Location` {object_uuid: "%s"})-' \
                '[:ENCOMPASSED_BY]->(e:`Location`) RETURN e.object_uuid' % (
                    object_uuid)
        res, _ = db.cypher_query(query)
        return [row[0] for row in res]

    @classmethod
    def get_single_encompassed_by(cls, object_uuid):
        query = 'MATCH (n:`Location` {object_uuid: "%s"})-' \
                '[:ENCOMPASSED_BY]->(e:`Location`) RETURN e.name' % (
                    object_uuid)
        res, _ = db.cypher_query(query)
        return res.one

    @classmethod
    def get_positions(cls, object_uuid):
        query = 'MATCH (l:`Location` {object_uuid: "%s"})-' \
                '[:POSITIONS_AVAILABLE]->(p:`Position`) RETURN ' \
                'p.object_uuid' % object_uuid
        res, _ = db.cypher_query(query)
        return [row[0] for row in res]
Example #17
0
class Publication(StructuredNode, NodeUtils):
    # Publication properties and relationships
    venueName = StringProperty()
    references = ArrayProperty()
    year = StringProperty()
    n_citation = StringProperty()
    venueID = StringProperty()
    fosWeights = ArrayProperty()
    authorNames = ArrayProperty()
    pubID = StringProperty(index=True)
    publisher = StringProperty()
    title = StringProperty()
    authorIDs = ArrayProperty()
    fosNames = ArrayProperty()
    doi = StringProperty()
    author = RelationshipTo('.author.Author', 'AUTHORED_BY')
    fos = RelationshipTo('.fos.FoS', 'IN_FIELD')
    publicationRel = RelationshipTo('.publication.Publication', 'REFERENCES')
    publisherRel = RelationshipTo('.publisher.Publisher', 'PUBLISHED_BY')
    venue = RelationshipTo('.venue.Venue', 'PUBLISHED_AT')

    @property
    def serialize(self):
        return {
            'node_properties': {
                'venueName': self.venueName,
                'references': self.references,
                'year': self.year,
                'venueID': self.venueID,
                'fosWeights': self.fosWeights,
                'authorNames': self.authorNames,
                'pubID': self.pubID,
                'publisher': self.publisher,
                'title': self.title,
                'authorIDs': self.authorIDs,
                'fosNames': self.fosNames,
                'doi': self.doi,
                'n_citation': self.n_citation
            },
        }

    @property
    def serialize_connections(self):
        return [
            {
                'nodes_type':
                'Publication',
                'nodes_related':
                self.serialize_relationships(self.publication.all()),
            },
            {
                'nodes_type': 'Author',
                'nodes_related':
                self.serialize_relationships(self.author.all()),
            },
            {
                'nodes_type': 'Venue',
                'nodes_related':
                self.serialize_relationships(self.venue.all()),
            },
            {
                'nodes_type':
                'Publisher',
                'nodes_related':
                self.serialize_relationships(self.publisher.all()),
            },
            {
                'nodes_type': 'FoS',
                'nodes_related': self.serialize_relationships(self.fos.all())
            },
        ]
Example #18
0
class Disease(StructuredNode):
    name = StringProperty(unique_index=True, required=True)
    ar_name = StringProperty()
    description = StringProperty()
    ar_description = StringProperty()
    has = RelationshipTo(Symptom, 'has')
Example #19
0
class User(StructuredNode):
    user_id = UniqueIdProperty()

    friends = Relationship('User', 'FRIEND')
    apps = RelationshipTo(App, 'OWNS', model=UserAppRel)
Example #20
0
class Doctor(StructuredNode):
    name = StringProperty(unique_index=True, required=True)
    ar_name = StringProperty()
    description = StringProperty()
    ar_description = StringProperty()
    covers = RelationshipTo(Disease, 'covers')
Example #21
0
class City(StructuredNode):
    name = StringProperty(unique_index=True)
    province = RelationshipTo(Province, "CityProvinceRel")
Example #22
0
class User(StructuredNode):
    name = StringProperty()
    gender = StringProperty()
    pregnancy = BooleanProperty()
    group = StringProperty()
    might_have = RelationshipTo(Symptom, 'might_have')
Example #23
0
class NeighborhoodNode(StructuredNode):
    name = StringProperty()
    community = RelationshipTo('DistrictNode', 'PART_OF')
    buildings = RelationshipFrom('BuildingNode', 'PART_OF')
Example #24
0
class BugzillaBug(EstuaryStructuredNode):
    """Definition of a Bugzilla bug in Neo4j."""

    assignee = RelationshipTo('.user.User',
                              'ASSIGNED_TO',
                              cardinality=ZeroOrOne)
    attached_advisories = RelationshipFrom('.errata.Advisory', 'ATTACHED')
    classification = StringProperty()
    creation_time = DateTimeProperty()
    id_ = UniqueIdProperty(db_property='id')
    modified_time = DateTimeProperty(index=True)
    priority = StringProperty()
    # Called product_name in case we want to use product as a relationship later on
    product_name = StringProperty()
    product_version = StringProperty()
    qa_contact = RelationshipTo('.user.User', 'QA_BY', cardinality=ZeroOrOne)
    related_by_commits = RelationshipFrom('.distgit.DistGitCommit', 'RELATED')
    reporter = RelationshipTo('.user.User',
                              'REPORTED_BY',
                              cardinality=ZeroOrOne)
    resolution = StringProperty()
    resolved_by_commits = RelationshipFrom('.distgit.DistGitCommit',
                                           'RESOLVED')
    reverted_by_commits = RelationshipFrom('.distgit.DistGitCommit',
                                           'REVERTED')
    severity = StringProperty()
    short_description = StringProperty()
    status = StringProperty()
    target_milestone = StringProperty()
    votes = IntegerProperty()

    @property
    def display_name(self):
        """Get intuitive (human readable) display name for the node."""
        return 'RHBZ#{0}'.format(self.id_)

    @property
    def timeline_datetime(self):
        """Get the DateTime property used for the Estuary timeline."""
        return self.creation_time

    @classmethod
    def find_or_none(cls, identifier):
        """
        Find the node using the supplied identifier.

        :param str identifier: the identifier to search the node by
        :return: the node or None
        :rtype: EstuaryStructuredNode or None
        """
        uid = identifier
        if uid.lower().startswith('rhbz'):
            uid = uid[4:]
        if uid.startswith('#'):
            uid = uid[1:]

        # If we are left with something other than digits, then it is an invalid identifier
        if not re.match(r'^\d+$', uid):
            raise ValidationError(
                '"{0}" is not a valid identifier'.format(identifier))

        return cls.nodes.get_or_none(id_=uid)
Example #25
0
class ApartmentNode(StructuredNode):
    number = StringProperty()
    floor = StringProperty()
    building = RelationshipTo(BuildingNode, 'PART_OF')
    persons = RelationshipFrom('PersonNode', 'LIVES_IN')
Example #26
0
class Data(StructuredNode, DataInterface):
    """
    Data Node
    
    The Data node provides arbitrary data in a key->value scheme and may be
    applicable to a user directly, or in relation to an application as well.
    """
    # properties
    key = StringProperty(required=True)
    value = JSONProperty()

    # relationships
    # outgoing relationships (may or may not exist)
    applies_to_application = RelationshipTo('.application.Application',
                                            'APPLIES_TO',
                                            cardinality=ZeroOrOne)

    # incoming relationships (should only ever be one of these)
    user = RelationshipFrom('.user.User', 'HAS_DATA', cardinality=ZeroOrOne)
    application = RelationshipFrom('.application.Application',
                                   'HAS_DATA',
                                   cardinality=ZeroOrOne)
    organization = RelationshipFrom('.organization.Organization',
                                    'HAS_DATA',
                                    cardinality=ZeroOrOne)
    group = RelationshipFrom('.group.Group', 'HAS_DATA', cardinality=ZeroOrOne)

    def to_object(self, *args, **kwargs) -> EData:
        data = EData(key=self.key, value=self.value)
        data._object = self
        return data

    @staticmethod
    def update_data_nodes(new_data, db_object, relationship):
        """
        Update data nodes
        
        :param new_data:
        :param db_object:
        :param relationship: The name of the attribute defining the relationship to connect the data node to
        :return:
        """
        if not hasattr(db_object, 'data') or not new_data:
            return

        existing_data = {d.to_object() for d in db_object.data.all()}
        existing_data_dict = {d.key: d for d in existing_data}
        for data_node in new_data:
            # they're the same
            if data_node in existing_data:
                continue
            # new value
            if data_node.key in existing_data_dict:
                existing_node = existing_data_dict.get(data_node.key)
                existing_node._object.value = data_node.value
                existing_node._object.save()
            # new node
            else:
                if data_node.key in ('_empty_', ''):
                    continue
                data_node._object = Data(key=data_node.key,
                                         value=data_node.value)
                data_node._object.save()
                rel = getattr(data_node._object, relationship)
                rel.connect(db_object)
        # deletions
        existing_data_keys = set(existing_data_dict.keys())
        new_data_keys = {d.key for d in new_data}
        deletions = existing_data_keys.difference(new_data_keys)
        for key in deletions:
            existing_data_dict[key]._object.delete()
Example #27
0
class BadgeGroup(SBObject):
    name = StringProperty()
    description = StringProperty()

    # relationships
    badges = RelationshipTo('sb_badges.neo_models.Badge', "HAS")
Example #28
0
class Donation(SBObject):
    """
    Donations are contributions made from one user to another. Initially this
    will be utilized solely to provide a way to store the donations between
    a user and a user waging a campaign. Eventually we will be utilizing this
    or a derivative of it to also help track donations made to groups, higher
    reputation users, and projects.

    If a user's donation goes over the amount needed for the goal and the
    campaigner is on their first goal or has provided an update on the
    previous goal we release all the funds pledged, we do not attempt to break
    them up. However any donations pledged after that release will result
    in the same process of not being released until the next goal threshold
    is crossed and an update has been provided.
    If a donation is provided that spans x goals then the representative
    will need to provide x updates prior to receiving their next release
    """
    # Whether or not the donation has been delivered or has just been pledged
    # False if Pledged and True if executed upon
    completed = BooleanProperty(default=False)
    # Set as a float to enable change to be specified. Even though from an
    # interface perspective we probably want to maintain that donations of
    # 5, 10, 100, etc are made.
    # Amount is an Integer to adhere to Stripe's API and to ensure precision
    # http://stackoverflow.com/questions/3730019/why-not-use-double-or-
    # float-to-represent-currency
    amount = IntegerProperty(required=True)
    # optimization
    owner_username = StringProperty()
    stripe_charge_id = StringProperty()
    mission_type = StringProperty()
    # Owner
    # Access who created this donation through:
    # Neomodel: donations Cypher: DONATIONS_GIVEN
    # RelationshipTo('plebs.neo_models.Pleb')

    # relationships
    mission = RelationshipTo('sb_missions.neo_models.Mission',
                             "CONTRIBUTED_TO")
    quest = RelationshipTo('sb_quests.neo_models.Quest', "CONTRIBUTED_TO")

    # DEPRECATIONS
    # DEPRECATED: Rounds are deprecated and goals are no longer associated with
    # them. They are instead associated with Missions but are not aggregated
    # into rounds.
    owned_by = RelationshipTo('plebs.neo_models.Pleb', 'DONATED_FROM')

    @property
    def payment_method(self):
        # DO NOT USE: NON-USE PLACEHOLDER FOR SERIALIZER
        return None

    @classmethod
    def get_mission(cls, object_uuid):
        query = 'MATCH (d:Donation {object_uuid: "%s"})-' \
                '[:CONTRIBUTED_TO]->(mission:Mission) ' \
                'RETURN mission.object_uuid' % object_uuid
        res, _ = db.cypher_query(query)
        return res.one

    @classmethod
    def get_quest(cls, object_uuid):
        query = 'MATCH (d:Donation {object_uuid: "%s"})-' \
                '[:CONTRIBUTED_TO]->(mission:Mission)<-[:EMBARKS_ON]-' \
                '(quest:Quest) ' \
                'RETURN quest.object_uuid' % object_uuid
        res, _ = db.cypher_query(query)
        return res.one

    @classmethod
    def get_owner(cls, object_uuid):
        query = 'MATCH (d:`Donation` {object_uuid: "%s"}) ' \
                'RETURN d.owner_username' % object_uuid
        res, col = db.cypher_query(query)
        try:
            return res[0][0]
        except IndexError:
            return None
Example #29
0
class Country(StructuredNode):
    code = StringProperty(unique_index=True)
    inhabitant = RelationshipFrom(Person, 'IS_FROM')
    president = RelationshipTo(Person, 'PRESIDENT', cardinality=One)
Example #30
0
class Synopsis(StructuredNode):
    uid=UniqueIdProperty()
    summarizes = RelationshipTo('Session','SUMMARIZES')
    summarized = RelationshipFrom('Student','SUMMARIZED_BY')