Ejemplo n.º 1
0
class Organization(mongo.Document):
    id = mongo.UUIDField(required=False)
    name = mongo.StringField(max_length=255, required=True, unique=True)
    address = mongo.StringField(max_length=255, required=False)
    city = mongo.StringField(max_length=255, required=False)
    state = mongo.StringField(max_length=255, required=False)
    zip = mongo.StringField(max_length=50, required=False)
    point = mongo.PointField(required=False)
    phone = mongo.StringField(max_length=20, required=False)
    website = mongo.StringField(required=False)
    description = mongo.StringField(required=False)

    privacy = mongo.StringField(required=True, default='')
    last_updated = mongo.DateTimeField(required=True, default=datetime.datetime.now())
    created_by = mongo.StringField(required=False)

    def save(self, *args, **kwargs):
        self.last_updated = datetime.datetime.now()

        address = (self.address + ", " + self.zip, self.city, self.state)
        geocoded_addr = verify_address(address)
        if geocoded_addr != 'Error':
            self.point = geocoded_addr

        super(Organization, self).save(*args, **kwargs)

    def location_count(self):
        return Location.objects.filter(org=str(self.id)).count()

    def location_set(self):
        return Location.objects.filter(org=str(self.id))
Ejemplo n.º 2
0
class DataSourceMongoDocument(MongoDocument):
    meta = {'allow_inheritance': True, 'abstract': True, 'indexes': ['datetime', 'user']}

    user = mongo.ReferenceField(User, reverse_delete_rule=mongo.CASCADE)
    datetime: datetime = mongo.DateTimeField(default=datetime.utcnow)
    coordinates = mongo.PointField()
    geohash = mongo.StringField()

    @abstractmethod
    def compute_happiness_level(self):
        pass

    @property
    def data_source(self):
        raise NotImplementedError

    def save(self, **kwargs):
        super().save(**kwargs)
        start_date = self.datetime.date()
        end_date = start_date + timedelta(days=1)
        happiness_levels = [emotions_result.compute_happiness_level() for emotions_result
                            in self.__class__.objects(user=self.user, datetime__gte=start_date, datetime__lt=end_date)]
        average = np.mean(happiness_levels)
        try:
            happiness = HappinessLevel.objects.get(user=self.user, date__gte=start_date, date__lt=end_date)
        except mongo.DoesNotExist:
            happiness = HappinessLevel(user=self.user, date=start_date)
        setattr(happiness, f'{self.data_source}_happiness_level', average)

        happiness.compute_mean()
Ejemplo n.º 3
0
class Event(Base):
    name = mongoengine.StringField()
    description = mongoengine.StringField()
    location = mongoengine.PointField()
    date_time = mongoengine.DateTimeField()
    categories = mongoengine.ListField(mongoengine.ReferenceField(Category))

    def __init__(self,
                 name='',
                 description='',
                 location=(0, 0),
                 date_time=0,
                 categories=None,
                 *args,
                 **values):
        super().__init__(*args, **values)
        self.name = name
        self.description = description
        self.location = location
        self.date_time = date_time
        self.categories = categories

    def to_json(self, *args, **kwargs):
        cats = [str(cat_ref.id) for cat_ref in self.categories]

        return {
            "id": str(self.id),
            "name": self.name,
            "description": self.description,
            "location": self.location,
            "date_time": self.date_time,
            "category_ids": cats,
        }
Ejemplo n.º 4
0
class Fan(mclient.DynamicDocument):
    _id = mclient.ObjectIdField()
    user = mclient.StringField(max_length=255)
    currentPosition = mclient.PointField()
    friends = mclient.ListField(mclient.StringField(max_length=100))
    posts = mclient.EmbeddedDocumentListField(document_type=Post)
    meta = {'collection': 'Fans'}
Ejemplo n.º 5
0
class Locations(mongoengine.Document):
    location = mongoengine.PointField()
    moisture_data = mongoengine.ListField(
        mongoengine.ReferenceField(SoilMoisture, required=True))
    time = mongoengine.DateTimeField(default=datetime.datetime.now)

    def __unicode__(self):
        return "{} {} {}".format(self.location, self.moisture_data, self.time)
Ejemplo n.º 6
0
def findServiceArea(request, x, y, format=None):
    point = mongoengine.PointField([x, y])

    for loc in GeoJsonPolygon.objects.all():

        locations = loc.objects(point__geo_within=loc.geometry)

    return Response({"locations": locations})
Ejemplo n.º 7
0
class User(me.Document):
    DEFAULT_CONFIG = {
        # These match up with keys in praytimes.py
        "method": "ISNA",
        "asr": "Standard",
        # These don't
        "prayer_names": "standard"
    }
    user_token = me.StringField()
    timeline_token = me.StringField()
    location = me.PointField()
    location_geoname = me.StringField()
    tz_offset = me.IntField()
    created_at = me.DateTimeField()
    subscribed_at = me.DateTimeField()
    # It melted down when I tried name the db field "config"
    # Not sure what was up
    _sparse_config = me.DictField(db_field="sparse_config")

    def geocode(self):
        import requests
        res = requests.get('http://api.geonames.org/findNearbyPlaceNameJSON',
                           params={
                               'lat':
                               self.location[1],
                               'lng':
                               self.location[0],
                               'cities':
                               'cities1000',
                               'maxRows':
                               1,
                               'username':
                               os.environ.get('GEONAMES_USERNAME', 'demo')
                           })
        for place in res.json()["geonames"]:
            self.location_geoname = place["name"]

    @property
    def config(self):
        if not hasattr(self, "_config_inst"):
            self._config_inst = dict(self.DEFAULT_CONFIG)
            self._config_inst.update(self._sparse_config)
        return self._config_inst

    def save(self):
        # Paste _config_inst back into _sparse_config if reqd.
        if hasattr(self, "_config_inst"):
            # Transfer updated keys if not default
            for k, v in self._config_inst.items():
                if self.DEFAULT_CONFIG[k] != v:
                    self._sparse_config[k] = v
                elif k in self._sparse_config:
                    del self._sparse_config[k]
            # Remove deleted keys
            for k, v in self.DEFAULT_CONFIG.items():
                if k not in self._config_inst and k in self._sparse_config:
                    del self._sparse_config[k]
        super(User, self).save()
Ejemplo n.º 8
0
class Pano(me.Document):
    location = me.StringField()
    longlat = me.PointField(auto_index=True) # note that the coordinates are (long, lat) pairs
    heading = me.FloatField(default=None)
    fov = me.FloatField(default=90)
    pitch = me.FloatField(default=0)
    pano_id = me.StringField()
    image = me.ImageField()

    meta = {
        'indexes': ['pano_id']
    }

    @property
    def size(self):
        return self.image.size

    @property
    def url(self):
        loc = self.location or self.longlat
        return generate_pano_url(loc, self.heading, self.fov, self.pitch, self.size, self.pano_id)
    
    @property
    def image_md5(self):
        '''return the md5 hash of the stored image'''
        if self.image:
            return self.image.md5
        return None

    @property
    def PIL_image(self):
        if hasattr(self, '_PIL_image'):
            return self._PIL_image
        self._PIL_image = Image.open(cStringIO.StringIO(self.image.read()))
        return self._PIL_image

    @property
    def has_image(self):
        '''return False if the image is a null image'''
        return self.image_md5 != no_image_md5

    def show_image(self):
        return self.PIL_image.show()

    def __unicode__(self):
        return 'location=%r, longlat=%r, image_md5=%r' % (self.location, self.longlat['coordinates'], self.image_md5)

    @staticmethod
    def new_pano(location=None, heading=None, fov=90, pitch=0, size=(640, 640), pano_id=None, key=None):
        image = cStringIO.StringIO(get_pano(location, heading, fov, pitch, size, pano_id, key))
        params = dict(heading=heading, fov=fov, pitch=pitch, size=size, pano_id=pano_id, image=image)
        if isinstance(location, str):
            pano = Pano(location=location, **params)
        else:
            # location is provided as a (long, lat) pair
            pano = Pano(longlat=location, **params)
        return pano
Ejemplo n.º 9
0
class SampleSpecies(mongoengine.Document):
    original_id = mongoengine.StringField(required=True)
    smarter_id = mongoengine.StringField(required=True, unique=True)

    country = mongoengine.StringField(required=True)
    species = mongoengine.StringField(required=True)
    breed = mongoengine.StringField(required=True)
    breed_code = mongoengine.StringField(min_length=3)

    # required to search a sample relying only on original ID
    dataset = mongoengine.ReferenceField(Dataset,
                                         db_field="dataset_id",
                                         reverse_delete_rule=mongoengine.DENY)

    # track the original chip_name with sample
    chip_name = mongoengine.StringField()

    # define enum types for sex
    sex = mongoengine.EnumField(SEX)

    # GPS location
    # NOTE: X, Y where X is longitude, Y latitude
    location = mongoengine.PointField()

    # additional (not modelled) metadata
    metadata = mongoengine.DictField(default=None)

    # for phenotypes
    phenotype = mongoengine.EmbeddedDocumentField(Phenotype, default=None)

    meta = {
        'abstract': True,
    }

    def save(self, *args, **kwargs):
        """Custom save method. Deal with smarter_id before save"""

        if not self.smarter_id:
            logger.debug(f"Determining smarter id for {self.original_id}")

            # get the pymongo connection object
            conn = mongoengine.connection.get_db(alias=DB_ALIAS)

            # even is species, country and breed are required fields for
            # SampleSpecies document, their value will not be evaluated until
            # super().save() is called. I can't call it before determining
            # a smarter_id
            self.smarter_id = getSmarterId(self.species, self.country,
                                           self.breed, conn)

        # default save method
        super(SampleSpecies, self).save(*args, **kwargs)

    def __str__(self):
        return f"{self.smarter_id} ({self.breed})"
Ejemplo n.º 10
0
Archivo: map.py Proyecto: ynassar/pinit
class Map(mongoengine.Document):
    robot_name = mongoengine.StringField()
    resolution = mongoengine.DecimalField(min_value=0)
    height = mongoengine.IntField(min_value=0)
    width = mongoengine.IntField(min_value=0)
    b64_image = mongoengine.StringField()
    raw_map = mongoengine.StringField()
    origin = mongoengine.PointField()
    origin_angle_shift = mongoengine.FloatField()
    shift_x = mongoengine.FloatField()
    shift_y = mongoengine.FloatField()
Ejemplo n.º 11
0
class POI(me.Document):
  """ Implements a point of interest. """

  name = me.StringField(required=True)
  point = me.PointField(required=True)

  def __str__(self):

    return ("'" + self.name
      + "' (x=" + str(self.point['coordinates'][0])
      +  ", y=" + str(self.point['coordinates'][1]) + ")")
Ejemplo n.º 12
0
class User(gj.Document):
    meta = {'queryset_class': fm.BaseQuerySet}

    uid = db.StringField()
    nick_name = db.StringField()
    sex = db.StringField()
    birthed_at = db.LongField()
    height = db.IntField()
    body_id = db.IntField()
    occupation = db.StringField()
    education = db.StringField()
    religion_id = db.IntField()
    drink_id = db.IntField()
    smoking_id = db.IntField()
    blood_id = db.IntField()
    r_token = db.StringField()
    location = db.PointField()
    introduction = db.StringField()
    joined_at = db.LongField()
    last_login_at = db.LongField()
    job = db.StringField()
    area = db.StringField()
    phone = db.StringField()
    user_images = db.SortedListField(db.EmbeddedDocumentField(UserImage),
                                     ordering="index")
    user_images_temp = db.SortedListField(db.EmbeddedDocumentField(UserImage),
                                          ordering="index")
    charm_ids = db.ListField(db.IntField())
    ideal_type_ids = db.ListField(db.IntField())
    interest_ids = db.ListField(db.IntField())

    available = db.BooleanField(default=False)
    status = db.IntField(default=0)  # -10, 0, 10

    @property
    def posts(self):
        posts = Post.objects(author=self).order_by("-created_at").all()
        for post in posts:
            post.favorite_users = []
            post.comments.sort(key=lambda x: x.created_at, reverse=True)
        return posts

    def list_requests_like_me(self, response=None):
        return Request.objects(user_to=self, response=response).all()

    def list_requests_i_like(self, response=None):
        return Request.objects(user_from=self, response=response).all()

    def list_chat_rooms(self):
        return ChatRoom.objects(members=self).all()

    def list_users_rated_me_high(self):
        star_ratings = StarRating.objects(user_to=self, score__gte=4).all()
        return [star_rating.user_from for star_rating in star_ratings]
class ParkingSpot(mongoengine.Document):
    meta = {'collection': 'parking_spots'}

    # schema
    address = mongoengine.StringField()
    location = mongoengine.PointField()

    def fetch(self):
        """
        Fetches doc and parses id
        :return: doc
        """
        doc = self.to_mongo()
        doc['_id'] = str(doc['_id'])
        return doc
Ejemplo n.º 14
0
    class Segment(me.Document):
        segment_id = me.IntField(unique=True)
        label = me.StringField()
        length = me.FloatField()
        segment = me.LineStringField()  # GeoJSON LineString.
        midpoint = me.PointField()  # GeoJSON PointField.
        vehicles = me.ListField(me.ReferenceField('VehicleSegmentData'))
        running_average_speed = me.FloatField()
        running_average_travel_time = me.FloatField()
        last_updated = me.ComplexDateTimeField()

        meta = {
            'collection': config['MONGODB_SEGMENT_COLLECTION'],
            'indexes': ['segment_id', 'last_updated']
        }
Ejemplo n.º 15
0
class Event(Base):
    name = mongoengine.StringField()
    description = mongoengine.StringField()
    location = mongoengine.PointField()
    date_time = mongoengine.DateTimeField()
    categories = mongoengine.ListField(mongoengine.ReferenceField(Category))

    def __init__(self,
                 name='',
                 description='',
                 location=(0, 0),
                 date_time=0,
                 categories=None,
                 *args,
                 **values):
        super().__init__(*args, **values)
        self.name = name
        self.description = description
        self.location = location
        self.date_time = date_time
        self.categories = categories
    class VehicleSegmentData(me.Document):
        # vehicle data is tied to segment
        vehicle_id = me.IntField(null=True)
        vehicle_datetime = me.ComplexDateTimeField()
        vehicle_location = me.PointField()
        vehicle_segment_speed = me.FloatField()
        vehicle_segment_travel_time = me.FloatField()

        segment = me.ReferenceField('Segment')
        meta = {
            'collection':
            config['MONGODB_VEHICLE_COLLECTION'],
            'indexes': [
                'vehicle_datetime', {
                    "fields": ['vehicle_id'],
                    "unique": True,
                    "partialFilterExpression": {
                        "vehicle_id": {
                            "$type": "int"
                        }
                    }
                }
            ]
        }
Ejemplo n.º 17
0
class Coordinate(mongoengine.EmbeddedDocument):
    epsg = mongoengine.StringField(required=True, default='EPSG:2278')
    coordinate = mongoengine.PointField(required=True)
Ejemplo n.º 18
0
def test_should_point_convert_field():
    graphene_type = convert_mongoengine_field(mongoengine.PointField())
    assert isinstance(graphene_type, graphene.Field)
    assert isinstance(graphene_type.type.type, graphene.String)
    assert isinstance(graphene_type.type.coordinates, graphene.List)
Ejemplo n.º 19
0
class Child(Parent):

    meta = {'collection': 'test_child'}
    baz = mongoengine.StringField()
    loc = mongoengine.PointField()
Ejemplo n.º 20
0
class AnotherChild(Parent):

    meta = {"collection": "test_parent"}
    qux = mongoengine.StringField()
    loc = mongoengine.PointField()
Ejemplo n.º 21
0
class Jail(me.Document):
    name = me.StringField(required=True)
    location = me.PointField(required=True)
    state = me.StringField()
Ejemplo n.º 22
0
class Child(Parent):

    meta = {"collection": "test_child"}
    baz = mongoengine.StringField()
    loc = mongoengine.PointField()
Ejemplo n.º 23
0
class Ride(me.Document):
    pickup_datetime = me.DateTimeField()
    dropoff_datetime = me.DateTimeField()
    pickup_zipcode = me.IntField()
    pickup_borough = me.StringField()
    pickup_county = me.StringField()
    pickup_long_lat = me.PointField()
    dropoff_zipcode = me.IntField()
    dropoff_borough = me.StringField()
    dropoff_county = me.StringField()
    dropoff_long_lat = me.PointField()
    total_amount = me.FloatField()
    fare_amount = me.FloatField()
    tip_amount = me.FloatField()
    passenger_count = me.IntField()
    trip_distance = me.FloatField()

    @me.queryset_manager
    def pickups_nearby(doc_cls, queryset, long, lat, distance):
        return queryset.filter(
            pickup_long_lat__near=[long, lat],
            pickup_long_lat__max_distance=distance).order_by(
                '-pickup_datetime')

    @me.queryset_manager
    def dropoffs_nearby(doc_cls, queryset, long, lat, distance):
        return queryset.filter(
            dropoff_long_lat__near=[long, lat],
            dropoff_long_lat__max_distance=distance).order_by(
                '-dropoff_datetime')

    def to_json(self):
        response = {
            "pickup_datetime": self.pickup_datetime,
            "dropoff_datetime": self.dropoff_datetime,
            "pickup_zipcode": self.pickup_zipcode,
            "pickup_borough": self.pickup_borough,
            "pickup_county": self.pickup_county,
            "pickup_long_lat": self.pickup_long_lat['coordinates'],
            "dropoff_zipcode": self.dropoff_zipcode,
            "dropoff_borough": self.dropoff_borough,
            "dropoff_county": self.dropoff_county,
            "dropoff_long_lat": self.dropoff_long_lat['coordinates'],
            "total_amount": self.total_amount,
            "fare_amount": self.fare_amount,
            "tip_amount": self.tip_amount,
            "passenger_count": self.passenger_count,
            "trip_distance": self.trip_distance
        }
        return response

    def to_series(self):
        response = pd.Series({
            "pickup_datetime":
            self.pickup_datetime,
            "dropoff_datetime":
            self.dropoff_datetime,
            "pickup_zipcode":
            self.pickup_zipcode,
            "pickup_borough":
            self.pickup_borough,
            "pickup_county":
            self.pickup_county,
            "pickup_long_lat":
            self.pickup_long_lat['coordinates'],
            "dropoff_zipcode":
            self.dropoff_zipcode,
            "dropoff_borough":
            self.dropoff_borough,
            "dropoff_county":
            self.dropoff_county,
            "dropoff_long_lat":
            self.dropoff_long_lat['coordinates'],
            "total_amount":
            self.total_amount,
            "fare_amount":
            self.fare_amount,
            "tip_amount":
            self.tip_amount,
            "passenger_count":
            self.passenger_count,
            "trip_distance":
            self.trip_distance
        })
        return response

    meta = {
        'indexes': [[("pickup_long_lat", "2dsphere"), ("pickup_datetime", 1)],
                    [("dropoff_long_lat", "2dsphere"),
                     ("dropoff_datetime", 1)],
                    [("pickup_datetime", 1), ("pickup_borough", 1),
                     ("pickup_zipcode", 1)],
                    [("dropoff_datetime", 1), ("dropoff_borough", 1),
                     ("dropoff_zipcode", 1)],
                    [("pickup_datetime", 1), ("pickup_long_lat", "2dsphere")],
                    [("dropoff_datetime", 1),
                     ("dropoff_long_lat", "2dsphere")]],
        'collection':
        'rides_15'
    }
Ejemplo n.º 24
0
class MongoDescriptor(me.Document):
    photo_id = me.LongField(primary_key=True, required=True)
    coords = me.PointField(db_field="coordinates", required=True)
    dataset = me.EnumField(DatasetEnum, required=True)
    binary_descriptor = me.BinaryField(required=True, db_field="descriptor")
    meta = {'collection': 'flickr.descriptors_512'}

    @property
    def descriptor(self):
        if self.binary_descriptor is not None:
            return pickle.loads(self.binary_descriptor)
        else:
            return None

    @descriptor.setter
    def descriptor(self, descriptor_array: np.ndarray):
        if not isinstance(descriptor_array, np.ndarray):
            raise ValueError("Descriptor array should be of type np.ndarray")
        self.binary_descriptor = pickle.dumps(descriptor_array, protocol=2)

    @property
    def coordinates(self):
        return self.coords['coordinates']

    @coordinates.setter
    def coordinates(self, coord_dict):
        if 'lat' not in coord_dict or 'lng' not in coord_dict:
            raise ValueError(
                "error setting coordinates, lat or lng is not in dict")
        self.coords = [coord_dict['lng'], coord_dict['lat']]

    def set_coordinates(self, lng, lat):
        self.coords = [lng, lat]

    @classmethod
    def get_ids_and_coords(cls, dataset: DatasetEnum) -> dict:
        if isinstance(dataset, DatasetEnum):
            objects = cls.objects(dataset=dataset)
        else:
            raise ValueError(
                f"dataset should be one of DatasetEnum, was {dataset}")
        total = objects.count()

        log.debug(
            f"Getting {dataset.value} dataset from db. Total number of documents in db {total}"
        )

        ids = np.zeros(shape=total, dtype=int)
        coordinates = np.zeros(shape=(total, 2))

        batch_size = 100000
        for i, descriptor in enumerate(
                objects.batch_size(batch_size).only('photo_id', 'coords')):
            ids[i] = descriptor.photo_id
            coordinates[i, :] = descriptor.coordinates

            if (i + 1) % batch_size == 0:
                log.debug(f"Processed {i + 1} documents")

        return ids, coordinates

    @classmethod
    def get_data_as_arrays(cls, dataset: DatasetEnum = None) -> dict:
        if isinstance(dataset, DatasetEnum):
            objects = cls.objects(dataset=dataset)
        else:
            raise ValueError(
                f"dataset should be one of DatasetEnum, was {dataset}")

        total = objects.count()
        dim = cls.objects.first().descriptor.shape[0]

        log.debug(
            f"Getting {dataset.value} dataset from db. Total number of documents in db {total}"
        )

        descriptors = np.zeros(shape=(total, dim))
        ids = np.zeros(shape=total, dtype=int)
        coordinates = np.zeros(shape=(total, 2))
        batch_size = 50000
        for i, descriptor in enumerate(objects.batch_size(batch_size)):
            descriptors[i, :] = descriptor.descriptor
            ids[i] = descriptor.photo_id
            coordinates[i, :] = descriptor.coordinates

            if (i + 1) % batch_size == 0:
                log.debug(f"Processed {i + 1} documents")

        return ids, coordinates, descriptors

    @classmethod
    def get_random_docs(cls, dataset, sample_size):
        # Sample is quite slow, don't suggest using it
        pipeline = [{
            "$sample": {
                "size": sample_size
            }
        }, {
            "$project": {
                '_id': 1
            }
        }]
        pipeline_cursor = cls.objects(dataset=dataset).aggregate(pipeline)

        ids = [doc['_id'] for doc in pipeline_cursor]

        return cls.objects(photo_id__in=ids)
Ejemplo n.º 25
0
 class Doc(me.Document):
     point = me.PointField()
Ejemplo n.º 26
0
class Restaurant(mongo.DynamicDocument):
    name = mongo.StringField(required=True)
    address = mongo.StringField(required=True)
    email = mongo.EmailField()
    geolocation = mongo.PointField()
    description = mongo.StringField(max_length=TWEET_CHAR_LENGTH)
Ejemplo n.º 27
0
class User(mongo.Document):
    meta = {'queryset_class': CustomUserQuerySet, 'allow_inheritance': True}

    full_name = mongo.StringField(verbose_name=_('full name'), max_length=30)
    email = mongo.EmailField(verbose_name=_('email address'),
                             required=True,
                             unique=True)
    password = mongo.StringField(max_length=128, verbose_name=_('password'))
    last_login = mongo.DateTimeField(verbose_name=_('last login'),
                                     default=timezone.now)
    is_staff = mongo.BooleanField(default=False)
    is_active = mongo.BooleanField(default=True)
    is_superuser = mongo.BooleanField(default=False)
    site_id = mongo.IntField(required=True, default=settings.SITE_ID)
    current_role = mongo.StringField(required=False)

    image = mongo.StringField(required=False)
    user_types = mongo.ListField(mongo.ReferenceField(UserTypes),
                                 required=True,
                                 verbose_name=_('User Types'))
    primary_user_type = mongo.ReferenceField(
        UserTypes, required=False, verbose_name=_('Primary User Type'))
    organization = mongo.ReferenceField(Organization,
                                        required=False,
                                        verbose_name=_('Organization'))
    custom_field_form = mongo.ReferenceField("FormSchema", required=False)
    activation_key = mongo.StringField(required=False)
    key_expires = mongo.DateTimeField(required=False)

    ban = mongo.BooleanField(default=False)
    ban_reason = mongo.StringField(max_length=255, required=False)

    address = mongo.StringField(max_length=255, required=False)
    city = mongo.StringField(max_length=255, required=False)
    state = mongo.StringField(max_length=255, required=False)
    zip = mongo.StringField(max_length=50, required=False)
    phone = mongo.StringField(max_length=20, required=False)
    description = mongo.StringField(required=False)
    point = mongo.PointField(required=False)

    #used for dashboard resource reference
    dashboard_resource_id = mongo.StringField(max_length=24, required=False)
    # TODO disabled for now, either needs to become a custom form, or hard coded like the address above
    # billing_phone = mongo.StringField(max_length=20, required=False, verbose_name=_('Billing Phone'))
    # shipping_phone = mongo.StringField(max_length=20, required=False, verbose_name=_('Shipping Phone'))

    # same_address = mongo.BooleanField(default=False, verbose_name=_('Is shipping adddress same as billing address'))
    # address_verified = mongo.BooleanField(default=False, verbose_name=_('Address verified by TaxCloud'))

    created = mongo.StringField(required=True, default=str(datetime.now()))
    updated = mongo.StringField(required=True, default=str(datetime.now()))

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['full_name']

    @mongo.queryset.queryset_manager
    def objects(doc_cls, queryset):
        # This may actually also be done by defining a default ordering for
        # the document, but this illustrates the use of manager methods
        return queryset.filter(site_id=settings.SITE_ID)

    @mongo.queryset.queryset_manager
    def all(doc_cls, queryset):
        # This may actually also be done by defining a default ordering for
        # the document, but this illustrates the use of manager methods
        return queryset.all()

    def save(self, *args, **kwargs):
        self.updated = datetime.now().strftime("%Y-%m-%d %H:%M:%S")

        if self.address and self.zip and self.city and self.state:
            address = (self.address + ", " + self.zip, self.city, self.state)
            geocoded_addr = verify_address(address)
            if geocoded_addr != 'Error':
                self.point = geocoded_addr

        super(User, self).save(*args, **kwargs)

        if not self.primary_user_type:
            self.set_primary_user_type()

    def set_current_role(self, role):
        self.current_role = role
        self.save()

    def set_primary_user_type(self, typ=None):
        admin = UserTypes.objects.get(name='Admin')
        if typ:
            typ = UserTypes.objects.get(name=typ)
        elif admin in self.user_types:
            typ = admin
        else:
            typ = self.user_types[0]
        self.primary_user_type = typ
        if self.site_id == 1:
            self.current_role = 'maps-admin'
        else:
            self.current_role = typ.name
        self.save()

    # def is_provider(self):
    #     return len(self.user_types.filter(type='provider')) > 0

    def get_username(self):
        "Return the identifying username for this User"
        return getattr(self, self.USERNAME_FIELD)

    def __unicode__(self):
        return self.get_username()

    def natural_key(self):
        return (self.get_username(), )

    def is_anonymous(self):
        """
        Always returns False. This is a way of comparing User objects to
        anonymous users.
        """
        return False

    def is_authenticated(self):
        """
        Always return True. This is a way to tell if the user has been
        authenticated in templates.
        """
        return True

    def set_password(self, raw_password):
        self.password = make_password(raw_password)

    def check_password(self, raw_password):
        """
        Returns a boolean of whether the raw_password was correct. Handles
        hashing formats behind the scenes.
        """
        def setter(raw_password):
            self.set_password(raw_password)
            self.save(update_fields=["password"])

        return check_password(raw_password, self.password, setter)

    def set_unusable_password(self):
        # Sets a value that will never be a valid hash
        self.password = make_password(None)

    def has_usable_password(self):
        return is_password_usable(self.password)

    def get_session_auth_hash(self):
        """
        Returns an HMAC of the password field.
        """
        key_salt = "maps.users.models.AbstractBaseUser.get_session_auth_hash"
        return salted_hmac(key_salt, self.password).hexdigest()

    def email_user(self, subject, message, from_email=None, **kwargs):
        """
        Sends an email to this User.
        """
        send_mail(subject, message, from_email, [self.email], **kwargs)

    @property
    def location_count(self):
        try:
            return Location.objects(created_by=str(self.id)).count()
        except mongo.ValidationError:
            return 0

    @property
    def image_url(self):
        url = None
        if self.image:
            url = settings.MEDIA_URL + self.image
        return url

    def custom_form(self):
        output = []
        try:
            if self.custom_field_form:
                serializer = FormSchemaIdSerializer(self.custom_field_form)
                output.append(serializer.data)
        except:
            pass
        return output

    def has_permission(self, obj_name, action):
        for ut in self.user_types:
            if ut.has_permission(obj_name, action):
                return True

        return False

    def has_edit_other_permission(self, obj_name):
        return self.has_permission(obj_name, '4')

    def has_delete_other_permission(self, obj_name):
        return self.has_permission(obj_name, '5')

    def has_edit_own_permission(self, obj_name):
        return self.has_permission(obj_name, '1')

    def has_delete_own_permission(self, obj_name):
        return self.has_permission(obj_name, '2')

    def can_delete(self, obj, perm_type=None):
        if not perm_type:
            perm_type = obj.permission_type

        if obj.created_by == self.id:
            if self.has_delete_own_permission(perm_type):
                return True
        else:
            if self.has_delete_other_permission(perm_type):
                return True
        return False

    def can_edit(self, obj, perm_type=None):
        if not perm_type:
            perm_type = obj.permission_type

        if obj.created_by == self.id:
            if self.has_edit_own_permission(perm_type):
                return True
        else:
            if self.has_edit_other_permission(perm_type):
                return True
        return False

    @property
    def permission_type(self):
        return "users"
Ejemplo n.º 28
0
class User(db.Document):
    meta = {
        'strict': False,
        'queryset_class': fm.BaseQuerySet,
        'index_opts': INDEX_OPTS,
        'index_background': INDEX_BACKGROUND,
        'index_cls': INDEX_CLS,
        'auto_create_index': AUTO_CREATE_INDEX,
        'indexes': [
            # 'uid',
            # 'phone',
            # '-last_login_at',
            # (("location", "2dsphere"), '-birthed_at'),
            # (("location", "2dsphere"), '-birthed_at', '-star_rating_avg'),
        ]
    }

    class Status(object):
        OPENED = "OPENED"
        PENDING = "PENDING"
        APPROVED = "APPROVED"
        REJECTED = "REJECTED"
        BLOCKED = "BLOCKED"
        UNREGISTERED = "UNREGISTERED"

    uid = db.StringField()
    nickname = db.StringField()
    sex = db.StringField(choices=["M", "F"])
    birthed_at = db.LongField()
    height = db.IntField()
    body_id = db.IntField()
    occupation = db.StringField()
    education = db.StringField()
    religion_id = db.IntField()
    drink_id = db.IntField()
    smoking_id = db.IntField()
    blood_id = db.IntField()
    device_token = db.StringField()
    location = db.PointField()
    introduction = db.StringField()
    joined_at = db.LongField()
    last_login_at = db.LongField()
    job = db.StringField()
    area = db.StringField()
    phone = db.StringField(unique=True)

    user_images = db.SortedListField(db.EmbeddedDocumentField(UserImage), ordering="index")
    user_images_temp = db.SortedListField(db.EmbeddedDocumentField(UserImage), ordering="index")

    charm_ids = db.ListField(db.IntField())
    ideal_type_ids = db.ListField(db.IntField())
    interest_ids = db.ListField(db.IntField())

    available = db.BooleanField(default=False)
    status = db.StringField(choices=[
        Status.OPENED,
        Status.PENDING,
        Status.APPROVED,
        Status.REJECTED,
        Status.BLOCKED,
        Status.UNREGISTERED
    ])
    star_rating_avg = db.FloatField(default=0)

    free_pass_tokens = db.ListField(db.LongField(), default=[0, 0])
    free_open_tokens = db.ListField(db.LongField(), default=[0])

    is_phones_cached = False
    phones_cache = []

    def identify(self, request):
        uid = request.headers.get("uid", None)
        if self.uid != uid:
            raise abort(401)

    def list_posts(self) -> list:
        result = Post.list_posts(author=self.id, is_deleted=False)
        return result

    def list_requests_to_me(self, response=None):
        return Request.list_requests(user_to=self, response=response)

    def list_requests_from_me(self, response=None):
        return Request.list_requests(user_from=self, response=response)

    def list_conversations(self):
        return Conversation.objects(participants=self).all()

    def list_users_rated_me(self):
        star_ratings = StarRating.objects(user_to=self).order_by("-rated_at").as_pymongo()
        score_repository = {
            str(s.get("user_from")): dict(score=s.get("score", 0), rated_at=s.get("rated_at")) for s in star_ratings
        }
        raters = User.list(id__in=score_repository.keys()).as_pymongo()

        result = []
        for rater in raters:
            user_id = str(rater.get("_id"))
            o = score_repository.get(user_id)
            o["user"] = rater
            result.append(o)

        return result

    def list_users_rated_me_high(self):
        star_ratings = StarRating.objects(user_to=self, score__gte=4).order_by("-rated_at").as_pymongo()
        user_ids = [star_rating.get("user_from", None) for star_rating in star_ratings]
        users_dict = User.get_users_dict(set(user_ids))
        result = [users_dict.get(str(user_id)) for user_id in user_ids]
        return filter(lambda x: x, result)

    def list_users_i_rated_high(self):
        star_ratings = StarRating.objects(user_from=self, score__gte=4).order_by("-rated_at").as_pymongo()
        user_ids = [star_rating.get("user_to", None) for star_rating in star_ratings]
        users_dict = User.get_users_dict(set(user_ids))
        result = [users_dict.get(str(user_id)) for user_id in user_ids]
        return filter(lambda x: x, result)

    def get_recommendation(self):
        recommendation = Recommendation.objects(owner=self).first()
        if not recommendation:
            recommendation = Recommendation(
                owner=self, user_ids=[], last_recommended_at=pendulum.yesterday().int_timestamp
            )
            recommendation.save()
            recommendation.reload()
        return recommendation

    def get_first_image(self):
        return self.user_images[0].url if self.user_images else ""

    def remove_user_from_recommendation(self, user_to_remove):
        if not user_to_remove:
            raise ValueError("owner and target must be required value.")
        recommendation = Recommendation.objects(owner=self).first()
        if not recommendation:
            return
        for index, rec_user_id in enumerate(recommendation.user_ids):
            if rec_user_id == user_to_remove.id:
                del recommendation.user_ids[index]
                break
        recommendation.save()

    def get_current_amount_of_point(self):
        payments = Payment.objects(owner=self).all()
        amount_sum = 0
        for payment in payments:
            amount_sum += payment.amount
        return amount_sum

    def is_available_for_free_pass_token(self):
        token_min = min(self.free_pass_tokens)
        current_time = pendulum.now().int_timestamp
        delta = current_time - token_min
        return delta >= 0

    def consume_free_pass_token(self):
        tokens = list(self.free_pass_tokens)
        index = tokens.index(min(tokens))
        tokens[index] = pendulum.now().int_timestamp + FREE_PASS_NEXT * 60 * 60
        if len(tokens) != 2:
            tokens = [0, 0]
        self.update(free_pass_tokens=tokens)

    def is_available_for_free_open_token(self):
        token_min = min(self.free_open_tokens)
        current_time = pendulum.now().int_timestamp
        delta = current_time - token_min
        return delta >= 0

    def consume_free_open_token(self):
        tokens = list(self.free_open_tokens)
        index = tokens.index(min(tokens))
        tokens[index] = pendulum.now().int_timestamp + FREE_OPEN_NEXT * 60 * 60
        if len(tokens) != 1:
            tokens = [0]
        self.update(free_open_tokens=tokens)

    def consume(self, amount):
        if amount <= 0:
            raise ValueError("Illegal amount found. The amount must be bigger than 0.")

        total_amount = self.get_current_amount_of_point()
        if total_amount < amount:
            raise Exception(
                "Not enough balance..\n"
                "remaining amount: {total_amount}, amount to consume: {amount}".format(
                    total_amount=total_amount, amount=amount))

        Payment(
            owner=self,
            type="CONSUME",
            amount=(amount * -1),
            created_at=pendulum.now().int_timestamp
        ).save()

    def purchase(self,
                 platform=None,
                 order_id=None,
                 product_id=None,
                 amount=None,
                 created_at=None,
                 purchase_time_ms=None):

        if not product_id or amount <= 0 or not order_id or not created_at or not purchase_time_ms or not platform:
            raise ValueError("Illegal amount found. The amount must be bigger than 0.")

        existing = Payment.objects(order_id=order_id, purchase_time_ms=purchase_time_ms).first()
        if existing:
            return Payment.Result.DUPLICATE

        payment = Payment(
            owner=self,
            type="PURCHASE",
            platform=platform,
            order_id=order_id,
            product_id=product_id,
            amount=amount,
            created_at=int(created_at),
            purchase_time_ms=int(purchase_time_ms)
        )
        payment.save()

        return Payment.Result.PURCHASED

    def list_payments(self, to_json=False):
        if not to_json:
            return Payment.objects(owner=self).all()
        else:
            payments = Payment.objects(owner=self).as_pymongo()
            return list(payments)

    def set_contact(self, phones):
        contact = self.get_contact()
        contact.phones = phones
        contact.last_updated = pendulum.now().int_timestamp
        contact.save()
        contact.reload()
        return contact

    def add_user_knows_me(self, user):
        contact = self.get_contact()
        user_ids_know_me = contact.user_ids_know_me
        if user.id not in user_ids_know_me:
            contact.user_ids_know_me.append(user.id)
            contact.save()

    def get_contact(self):
        contact = Contact.objects(owner=self).first()
        if not contact:
            contact = Contact(
                owner=self,
                phones=[],
                last_updated_at=pendulum.now().int_timestamp)
            contact.save()
            contact.reload()
        return contact

    def get_phones(self):
        if self.is_phones_cached:
            return self.phones_cache
        contact = self.get_contact()
        self.phones_cache = contact.phones
        self.is_phones_cached = True
        return self.phones_cache

    def has_in_contacts(self, phone) -> bool:
        if not phone:
            return False
        phones = self.get_phones()
        return phone in phones

    def does_know_each_other(self, user):
        if self.has_in_contacts(user.phone):  # checks whether I know him
            return True
        if user.has_in_contacts(self.phone):  # checks whether he knows me
            return True
        return False

    def _get_nin_ids(self) -> set:

        app.logger.debug("collecting nin ids..")
        nin_ids = set()
        # nin with requests
        requests_to_me = Request.objects(user_to=self).as_pymongo()
        requests_from_me = Request.objects(user_from=self).as_pymongo()
        to_me_ids = [r["user_from"] for r in requests_to_me]
        from_me_ids = [r["user_to"] for r in requests_from_me]
        nin_ids.update(to_me_ids)
        nin_ids.update(from_me_ids)

        app.logger.debug("collected nin ids with requests..")

        # nin with recommendation
        recommendation = self.get_recommendation()
        recommendation = recommendation.to_mongo()
        rec_ids = [user_id for user_id in recommendation["user_ids"]]
        nin_ids.update(rec_ids)

        app.logger.debug("collected nin ids with recommendation..")

        # nin with contact
        contact = self.get_contact()
        know_ids = [user_id for user_id in contact.user_ids_know_me]
        nin_ids.update(know_ids)
        phones = contact.phones
        ids_in_contacts = User.list_only_user_ids(phone__in=phones)
        nin_ids.update(ids_in_contacts)

        app.logger.debug("collected nin ids with contacts phone numbers..")

        return nin_ids

    def list_recommended_user_ids(self, nin_ids: set = None, result=None,
                                  min_diameter=0, max_diameter=30,
                                  star_rating_avg=3.5):
        """Generates recommended users. If not found, recursively try it increasing diameter up to 300 km."""
        sex = next((s for s in ['M', 'F'] if s != self.sex))
        result = result or []
        nin_ids = nin_ids or self._get_nin_ids()

        location = self.location["coordinates"] if self.location else [127.0977517240413, 37.49880740259655]
        params = dict(
            location__near=location,
            location__min_distance=min_diameter * 1000,
            location__max_distance=max_diameter * 1000,
            birthed_at__gte=self.birthed_at - (12 * ONE_YEAR_TO_SECONDS),
            birthed_at__lte=self.birthed_at + (12 * ONE_YEAR_TO_SECONDS),
            star_rating_avg__gte=star_rating_avg,
            id__nin=nin_ids,
            available=True,
            sex=sex
        )

        if max_diameter > 300:
            return result

        app.logger.debug("collecting users with params: {0}..".format(str(params)))

        cursor = User.list(**params)

        index = 0
        while True:
            app.logger.debug("cursor is moving..")
            user = _get_index_at(cursor, index)

            if user is None:
                break

            if self.does_know_each_other(user):
                self.add_user_knows_me(user)
                user.add_user_knows_me(self)
                nin_ids.add(user.id)
                continue
            result.append(user.id)
            index += 1
            if len(result) >= 2:
                break

        if len(result) < 2:
            app.logger.debug("Not enough recommended user found.. collecting more")
            return self.list_recommended_user_ids(
                nin_ids, result=result, star_rating_avg=star_rating_avg * 0.9,
                min_diameter=max_diameter, max_diameter=max_diameter * 2)

        return result  # 126.98265075683594, 37.56100082397461

    def list_realtime_user_ids(self):
        nin_ids = self._get_nin_ids()
        sex = 'M' if self.sex == 'F' else 'F'
        last_login_at_gte = pendulum.now().int_timestamp - (60 * 30)
        params = dict(
            last_login_at__gte=last_login_at_gte,
            id__nin=nin_ids,
            sex=sex,
            available=True
        )

        cursor = User.objects(**params).order_by("-last_login_at")
        size = cursor.count()

        result = []
        for index in range(0, size):
            user = cursor[index]
            if self.does_know_each_other(user):
                self.add_user_knows_me(user)
                user.add_user_knows_me(self)
                continue
            result.append(user.id)
            if len(result) >= 10:
                break
        return result

    @time_lapse
    def list_user_ids_within_distance(self, distance=5):
        nin_ids = self._get_nin_ids()
        sex = 'M' if self.sex == 'F' else 'F'

        location = self.location["coordinates"] if self.location else [127.0936859, 37.505808]
        params = dict(
            location__near=location,
            location__max_distance=distance * 1000,  # 1000 = 1 km
            location__min_distance=0 * 1000,
            birthed_at__gte=self.birthed_at - (12 * ONE_YEAR_TO_SECONDS),
            birthed_at__lte=self.birthed_at + (12 * ONE_YEAR_TO_SECONDS),
            id__nin=nin_ids,
            sex=sex,
            available=True
        )

        user_ids = User.list_only_user_ids(**params)
        random.seed(_get_hash(str(self.id)) + 1)
        random.shuffle(user_ids)

        result = []
        for user_id in user_ids:
            user = User.get(id=user_id)
            if self.does_know_each_other(user):
                self.add_user_knows_me(user)
                user.add_user_knows_me(self)
                continue
            result.append(user.id)
            if len(result) >= 10:
                break

        return result

    @classmethod
    def excludes(cls):
        return [
            "uid",
            "joined_at",
            "user_images_temp",
            "free_pass_tokens",
            "free_open_tokens",
            "phone"
        ]

    @classmethod
    def get(cls, **kwargs):
        excludes = kwargs.get("excludes", User.excludes())
        return User.objects.exclude(*excludes).get_or_404(**kwargs)

    @classmethod
    def list(cls, **kwargs):
        users = User.objects(**kwargs).exclude(*User.excludes())
        return users

    @classmethod
    def get_users_dict(cls, user_ids: set):
        users = User.list(id__in=list(user_ids)).as_pymongo()
        return {str(user.get("_id")): user for user in users}

    @classmethod
    def get_verified_user(cls, user_id, request):
        uid = request.headers.get("uid", None)
        user = User.get(uid=uid)
        if user_id != str(user.id):
            abort(401)
        return user

    @classmethod
    @time_lapse
    def list_only_user_ids(cls, **kwargs):
        query = User.objects(**kwargs).only("id").as_pymongo()
        return [o["_id"] for o in query]

    def is_admin(self):
        admin = Admin.objects(user=self).first()
        return admin is not None

    def withdraw(self):
        unregister = Unregister(nickname=self.nickname, uid=self.uid, phone=self.phone, user=self)
        unregister.save()

        self.uid = None
        self.phone = None
        self.device_token = None
        self.user_images = []
        self.user_images_temp = []
        self.available = False
        self.status = User.Status.REJECTED
        self.nickname = "탈퇴 한 회원"
        self.save()

        Post.objects(author=self).delete()
        # Comment.objects(owner=user).delete()
        # Request.objects(user_from=user).delete()
        # Request.objects(user_to=user).delete()
        # StarRating.objects(user_from=user).delete()
        # StarRating.objects(user_to=user).delete()
        # Contact.objects(owner=user).delete()
        # Alarm.objects(owner=user).delete()

    def get_setting(self):
        setting = Setting.objects(owner=self).first()
        if not setting:
            setting = Setting(owner=self)
            setting.save()
            setting.reload()
        return setting