Esempio n. 1
0
class ScreenshotShotOverride(APIModel):
  ENCRYPTED_ID_KEY_TOKEN = 'screenshot-override'

  screenshot_set = models.ForeignKey(ScreenshotSet, related_name='+', null=False, on_delete=models.DO_NOTHING)
  screenshot_shot = models.ForeignKey(ScreenshotShot, related_name='+', null=False, on_delete=models.DO_NOTHING)
  override_image = models.ForeignKey(Image, related_name='+', null=False, on_delete=models.DO_NOTHING)

  device_type = models.CharField(max_length=32)

  create_time = models.DateTimeField(auto_now_add=True)
  update_time = models.DateTimeField(auto_now=True)

  data = hstore_field.HStoreField(null=True)

  is_landscape = data.bool_property()

  class Meta:
    app_label = 'lk'
    unique_together = ('screenshot_shot', 'device_type')

  def to_dict(self):
    return {
      'imageUrl': self.override_image.image_url(),
      'deviceType': self.device_type,
      'orientation': self.is_landscape
    }
Esempio n. 2
0
class ScreenshotShot(APIModel):
  ENCRYPTED_ID_KEY_TOKEN = 'screenshot-shot'

  user = models.ForeignKey(User, related_name='+', null=True, on_delete=models.DO_NOTHING)
  screenshot_set = models.ForeignKey(ScreenshotSet, related_name='+', null=False, on_delete=models.DO_NOTHING)

  create_time = models.DateTimeField(auto_now_add=True)
  update_time = models.DateTimeField(auto_now=True)

  screenshot_image = models.ForeignKey(Image, related_name='+', null=False, on_delete=models.DO_NOTHING)
  background_image = models.ForeignKey(Image, related_name='+', null=True, on_delete=models.DO_NOTHING)

  config = hstore_field.HStoreField(null=True)

  label = config.string_property()
  label_position = config.string_property()

  font = config.string_property()
  font_size = config.int_property()
  font_weight = config.int_property()
  font_color = config.string_property()

  phone_color = config.string_property()
  background_color = config.string_property()

  tablet_is_landscape = config.bool_property()
  is_landscape = config.bool_property()

  def to_dict(self):
    return {
      'id': self.encrypted_id,
      'createTime': self.date_to_api_date(self.create_time),

      'screenshot': self.screenshot_image.to_dict(),
      'background': self.background_image and self.background_image.to_dict(),
      'backgroundColor': self.background_color,

      'overrides': self.get_overrides(),

      'label': self.label,
      'labelPosition': self.label_position,

      'font': self.font,
      'fontSize': self.font_size,
      'fontWeight': self.font_weight,
      'fontColor': self.font_color,

      'phoneColor': self.phone_color or 'black',

      'isLandscape': self.is_landscape
    }

  def get_overrides(self):
    overrides = ScreenshotShotOverride.objects.filter(screenshot_shot_id=self.id)
    devices = {}
    for override in overrides:
      devices[override.device_type] = override.to_dict()
    return devices
class AppStoreSalesReportNotification(APIModel):
    user = models.ForeignKey(User,
                             related_name='+',
                             on_delete=models.DO_NOTHING)

    create_time = models.DateTimeField(auto_now_add=True, db_index=True)

    data = hstore_field.HStoreField()

    email = data.string_property()
    my_email = data.bool_property()
    slack_channel_name = data.string_property()
    slack_webhook = data.bool_property()
class AppStoreReviewNotification(APIModel):
  app = models.ForeignKey(AppStoreApp, related_name='+', on_delete=models.DO_NOTHING)
  user = models.ForeignKey(User, related_name='+', on_delete=models.DO_NOTHING)

  create_time = models.DateTimeField(auto_now_add=True, db_index=True)

  data = hstore_field.HStoreField()

  email = data.string_property()
  my_email = data.bool_property()
  slack_channel_name = data.string_property()
  slack_webhook = data.bool_property()
  twitter_handle = data.string_property()

  reviews_count = data.int_property()
Esempio n. 5
0
class SDKAppStat(APIModel):
    class Meta:
        unique_together = (('app', 'hour'))

    user = models.ForeignKey(User,
                             related_name='+',
                             db_index=False,
                             on_delete=models.DO_NOTHING)

    app = models.ForeignKey(SDKApp,
                            related_name='+',
                            db_index=False,
                            on_delete=models.DO_NOTHING)
    create_time = models.DateTimeField(auto_now_add=True)

    hour = models.DateTimeField()
    data = hstore_field.HStoreField()
Esempio n. 6
0
class SDKSessionActivity(APIModel):
    class Meta:
        app_label = 'lk'
        index_together = (('user', 'create_time'), )

    user = models.ForeignKey(User,
                             related_name='+',
                             on_delete=models.DO_NOTHING)
    create_time = models.DateTimeField(auto_now_add=True)

    session = models.ForeignKey(SDKSession,
                                related_name='+',
                                on_delete=models.DO_NOTHING)

    kind = models.CharField(max_length=32)

    data = hstore_field.HStoreField()
    remote_addr = data.string_property()
Esempio n. 7
0
class SDKSession(APIModel):
    class Meta:
        app_label = 'lk'
        index_together = (('user', 'last_accessed_time'), )

    ENCRYPTED_ID_KEY_TOKEN = 'sdk-session'

    user = models.ForeignKey(User,
                             related_name='+',
                             on_delete=models.DO_NOTHING)
    create_time = models.DateTimeField(auto_now_add=True)
    last_upgrade_time = models.DateTimeField(auto_now_add=True, null=True)
    last_accessed_time = models.DateTimeField(auto_now_add=True)

    app = models.ForeignKey(SDKApp,
                            related_name='+',
                            on_delete=models.DO_NOTHING)
    app_version = models.CharField(max_length=32, null=True)
    app_build = models.CharField(max_length=32, null=True)
    app_build_debug = models.NullBooleanField(null=True)

    sdk_platform = models.CharField(max_length=8, null=True)
    sdk_version = models.CharField(max_length=32, null=True)

    os = models.CharField(max_length=3, null=True)
    os_version = models.CharField(max_length=16, null=True)
    hardware = models.CharField(max_length=32, null=True)

    screen_height = models.PositiveIntegerField(null=True)
    screen_width = models.PositiveIntegerField(null=True)
    screen_scale = models.FloatField(null=True)

    sdk_user = models.ForeignKey(SDKUser,
                                 null=True,
                                 on_delete=models.DO_NOTHING)

    screens = models.PositiveIntegerField(default=0)
    taps = models.PositiveIntegerField(default=0)
    visits = models.PositiveIntegerField(default=0)
    seconds = models.PositiveIntegerField(default=0)

    data = hstore_field.HStoreField(null=True)
Esempio n. 8
0
class SlackAccessToken(APIModel):
    class Meta:
        app_label = 'lk'
        # This should really be universally unique, but for testing's sake...
        unique_together = ('user', 'token')

    user = models.ForeignKey(User,
                             related_name='+',
                             on_delete=models.DO_NOTHING)

    create_time = models.DateTimeField(auto_now_add=True)
    invalidated_time = models.DateTimeField(null=True)

    # invalidated tokens become null
    token = models.CharField(max_length=512, null=True)
    scope = models.CharField(max_length=128, null=False)

    # for slack-webhook type connections
    webhook_data = hstore_field.HStoreField(null=True)
    webhook_url = webhook_data.string_property()
    webhook_channel = webhook_data.string_property()
    webhook_config_url = webhook_data.string_property()
Esempio n. 9
0
class AppStoreSalesReportSubscription(APIModel):
  ENCRYPTED_ID_KEY_TOKEN = 'appstore-sales-report-sub'

  create_time = models.DateTimeField(auto_now_add=True)
  update_time = models.DateTimeField(auto_now=True)

  latest_report_date = models.DateField(null=True)

  user = models.ForeignKey(User, related_name='+', on_delete=models.DO_NOTHING)
  enabled = models.BooleanField(default=False)
  invalidated_time = models.DateTimeField(null=True)

  data = hstore_field.HStoreField(null=True)

  email = data.string_property()
  my_email = data.bool_property()
  slack_url = data.string_property()

  slack_channel_id = data.string_property()
  slack_channel_name = data.string_property()

  def to_dict(self):
    d = {
      'id': self.encrypted_id,
      'createTime': self.date_to_api_date(self.create_time),
    }
    if self.email:
      d['email'] = self.email
    if self.my_email:
      d['myEmail'] = True
    if self.slack_url:
      d['slackUrl'] = self.slack_url
    if self.slack_channel_name:
      d['slackChannel'] = {
        'name': self.slack_channel_name,
      }
    return d
Esempio n. 10
0
class RuntimeConfigRule(APIModel):
    ENCRYPTED_ID_KEY_TOKEN = 'cloudconfiggintool'

    user = models.ForeignKey(User,
                             related_name='+',
                             on_delete=models.DO_NOTHING)
    create_time = models.DateTimeField(auto_now_add=True)
    sort_time = models.DateTimeField(auto_now_add=True)
    update_time = models.DateTimeField(auto_now=True, null=True)

    key = models.CharField(max_length=64)
    kind = models.CharField(max_length=8, choices=ConfigKind.choices())
    namespace = models.CharField(max_length=16, null=True)
    bundle_id = models.CharField(max_length=256, null=False)

    value = models.CharField(max_length=2048)
    description = models.CharField(max_length=2048, null=True)

    qualifiers = hstore_field.HStoreField(null=True)

    version = qualifiers.string_property()
    version_match = qualifiers.string_property()
    build = qualifiers.string_property()
    build_match = qualifiers.string_property()
    ios_version = qualifiers.string_property()
    ios_version_match = qualifiers.string_property()
    debug = qualifiers.bool_property()
    sdk_user_labels = qualifiers.string_property()

    @property
    def specificity(self):
        s = len(self.qualifiers or {})

        if self.version_match == MatchOperator.EQUAL:
            s += 1
        if self.build_match == MatchOperator.EQUAL:
            s += 1
        if self.ios_version_match == MatchOperator.EQUAL:
            s += 1

        return s

    @property
    def typed_value(self):
        if self.kind == ConfigKind.INT:
            return int(self.value)
        if self.kind == ConfigKind.FLOAT:
            return float(self.value)
        if self.kind == ConfigKind.BOOL:
            return self.value == '1'
        return self.value

    def set_typed_value(self, value):
        if self.kind == ConfigKind.INT:
            self.value = '%s' % value
        elif self.kind == ConfigKind.FLOAT:
            self.value = repr(value)
        elif self.kind == ConfigKind.BOOL:
            self.value = '%s' % int(value)
        else:
            self.value = value

    def to_dict(self):
        result = {
            'id': self.encrypted_id,
            'key': self.key,
            'kind': self.kind,
            'description': self.description,
            'createTime': self.date_to_api_date(self.create_time),
            'sortTime': self.date_to_api_date(self.sort_time),
            'updateTime': self.date_to_api_date(self.update_time),
            'value': self.typed_value,
        }
        if self.bundle_id:
            result['bundleId'] = self.bundle_id
        if self.version:
            result['version'] = self.version
        if self.version_match:
            result['versionMatch'] = self.version_match
        if self.build:
            result['build'] = self.build
        if self.build_match:
            result['buildMatch'] = self.build_match
        if self.ios_version:
            result['iosVersion'] = self.ios_version
        if self.ios_version_match:
            result['iosVersionMatch'] = self.ios_version_match
        return result
Esempio n. 11
0
class User(AbstractBaseUser, APIModel):
  # Set this to None to get the default key.
  ENCRYPTED_ID_KEY_TOKEN = None

  USERNAME_FIELD = 'email'
  REQUIRED_FIELDS = ['first_name', 'last_name']

  first_name = models.CharField(max_length=30, blank=True, null=True)
  last_name = models.CharField(max_length=30, blank=True, null=True)

  email = models.EmailField(null=True, unique=True)
  phone = models.CharField(max_length=30, null=True, unique=True)

  is_staff = False
  is_active = True
  is_superuser = models.BooleanField(default=False)

  date_joined = models.DateTimeField(auto_now_add=True)

  delete_time = models.DateTimeField(null=True)

  # Random user attributes we find out.
  data = hstore_field.HStoreField(null=True)

  app_versions = hstore_field.HStoreField(null=True)

  flags = BitField(default=0, flags=[
    'has_unverified_email',        # 0

    'unsubscribed_from_email',     # 1

    'any_reviews_ready',           # 2
    'any_reviews_pending',         # 3

    'has_reviews_onboarded',       # 4

    'beta_optin',                  # 5

    'has_review_monitor',          # 6
    'has_review_monitor_tweets',   # 7
    'has_screenshot_builder',      # 8
    'has_sales_monitor',           # 9

    'has_sales_report_ready',      # 10
    'has_sales_onboarded',         # 11

    'has_websites',                # 12

    'sent_beta_optin_email',       # 13

    'has_super_users',             # 14

    'has_config',                  # 15

    'has_sent_tracking_data',      # 16
  ])

  objects = UserManager()


  def set_unset_flags(self, set_flags=None, unset_flags=None):
    if not (set_flags or unset_flags):
      return

    flags_to_set_value = 0
    for flag in (set_flags or []):
      flags_to_set_value |= getattr(User.flags, flag)
      setattr(self.flags, flag, True)

    flags_to_unset_value = 0
    for flag in (unset_flags or []):
      flags_to_unset_value |= getattr(User.flags, flag)
      setattr(self.flags, flag, False)

    User.objects.filter(pk=self.id).update(flags=F('flags').bitor(flags_to_set_value).bitand(~flags_to_unset_value))
    self.invalidate_cache()

  def set_flags(self, set_flags):
    self.set_unset_flags(set_flags=set_flags)

  def unset_flags(self, unset_flags):
    self.set_unset_flags(unset_flags=unset_flags)

  def mark_has_unverified_email(self, marked=True):
    if bool(self.flags.has_unverified_email) == marked:
      return

    if marked:
      self.set_flags(['has_unverified_email'])
    else:
      self.unset_flags(['has_unverified_email'])

  def has_perm(self, perm, obj=None):
    return self.is_superuser

  def has_module_perms(self, app_label):
    return self.is_superuser

  @property
  def _names(self):
    return [n for n in (self.first_name, self.last_name) if n]

  @property
  def initials(self):
    names = self._names
    if names:
      initials = [n[:1] for n in names]
    else:
      if self.email:
        initials = [self.email[:1]]
    return (''.join(initials)).upper()

  @property
  def full_name(self):
    name = ' '.join(self._names)
    if name:
      return name
    if self.email:
      return self.email

  @property
  def medium_name(self):
    names = self._names
    if len(names) == 2:
      return '%s %s.' % (names[0], names[1][:1])
    if len(names) == 1:
      return names[0]
    if self.email:
      return self.email[:10] + '...'
    return None

  @property
  def short_name(self):
    names = self._names
    if len(names):
      return names[0]
    if self.email:
      return self.email[:8] + '...'
    return None

  def names_dict(self, first_last=False):
    names = {
      'short': self.short_name,
      'full': self.full_name,
      'initials': self.initials,
    }
    if first_last:
      names['first'] = self.first_name
      names['last'] = self.last_name
    return names

  #
  # CACHING
  #

  @classmethod
  def cache_key_for_id(cls, user_id):
    return 'lk_user:%d' % user_id

  #
  # HANDY PROPERTIES
  #


  @property
  def small_avatar_url(self):
    # FIXME(Taylor)
    # if self.gae_avatar_url:
    #   return self.gae_avatar_url + '=s200-c'
    return None

  @property
  def large_avatar_url(self):
    # FIXME(Taylor)
    # if self.gae_avatar_url:
    #   return self.gae_avatar_url + '=s640-c'
    return None

  @property
  def twitter_handles(self):
    return [x.handle for x in self.twitter_access_tokens_set.filter(invalidated_time__isnull=True)]

  @property
  def products_list(self):
    products = []
    if self.flags.has_review_monitor:
      products.append('reviews')
    if self.flags.has_screenshot_builder:
      products.append('screenshots')
    if self.flags.has_sales_monitor:
      products.append('sales')
    if self.flags.has_websites:
      products.append('websites')
    if self.flags.has_super_users:
      products.append('super_users')
    if self.flags.has_config:
      products.append('config')
    return products

  #
  # JSON
  #

  def to_dict(self):
    response = {
      'id': self.encrypted_id,

      'avatarUrls': {
        'small': self.small_avatar_url,
        'large': self.large_avatar_url,
      },

      'names': self.names_dict(first_last=True),

      'createTime': self.date_to_api_date(self.date_joined),
    }

    if self.email:
      response['email'] = self.email
      if self.flags.has_unverified_email:
        response['hasUnverifiedEmail'] = True

    if self.flags.any_reviews_pending and not self.flags.any_reviews_ready:
      response['reviewsPending'] = True

    if self.flags.has_sales_report_ready:
      response['salesReportReady'] = True


    # TODO(Taylor): Generalize this somehow?
    if not self.flags.has_reviews_onboarded:
      response['needsReviewsOnboarding'] = True
    if not self.flags.has_sales_onboarded:
      response['needsSalesOnboarding'] = True

    if self.flags.beta_optin:
      response['beta'] = True

    response['products'] = self.products_list

    return response

  def to_minimal_dict(self):
    response = {
      'id': self.encrypted_id,
      'avatarUrls': {
        'small': self.small_avatar_url,
        'large': self.large_avatar_url,
      },
      'names': self.names_dict(),
    }
    return response

  def __unicode__(self):
    return self.full_name
Esempio n. 12
0
class ScreenshotSet(APIModel):
  ENCRYPTED_ID_KEY_TOKEN = 'screenshot-set'

  user = models.ForeignKey(User, related_name='+', null=True, on_delete=models.DO_NOTHING)

  create_time = models.DateTimeField(auto_now_add=True)
  update_time = models.DateTimeField(auto_now=True)
  delete_time = models.DateTimeField(null=True, default=None)

  name = models.CharField(max_length=128)
  version = models.CharField(max_length=32)

  shot_count = models.PositiveIntegerField()

  decorated_images = None

  data = hstore_field.HStoreField(null=True)
  platform = data.string_property()

  @property
  def public_url(self):
    return '%sscreenshots/%s' % (settings.SITE_URL, self.encrypted_id)

  @property
  def as_image(self):
    return url2png_url(self.public_url)

  @property
  def app_store(self):
    if self.platform == "Android":
      return "Google Play"
    return "App Store"

  def tweet_text(self):
    content_format = u"Creating app store images for %s was so simple using Screenshot Builder"
    trimmed_content_length = 140 - text.TCO_URL_LENGTH - 1 - len(content_format % '')

    # Now ellipsize the content inside the quotes if necessary.
    name_version = '%s %s' % (self.name, self.version)
    if len(name_version) > trimmed_content_length:
      # - 1 here for ellipsis.
      name_version = u'%s…' % name_version[:trimmed_content_length - 1]

    return content_format % name_version

  @property
  def twitter_share_url(self):
    try:
      return urlutil.appendparams('https://twitter.com/share', text=self.tweet_text(), url=self.public_url)
    except UnicodeEncodeError:
      return None

  def to_dict(self):
    set_dict = {
      'id': self.encrypted_id,
      'createTime': self.date_to_api_date(self.create_time),
      'updateTime': self.date_to_api_date(self.update_time),

      'name': self.name,
      'version': self.version,

      'imageUrl': self.as_image,

      'twitterShareUrl': self.twitter_share_url,

      'shotCount': self.shot_count,

      'platform': self.platform,
      'appStore': self.app_store,
    }

    if self.decorated_images:
      set_dict['previewImages'] = [i.to_dict() for i in self.decorated_images]

    return set_dict
Esempio n. 13
0
class SDKUser(APIModel):
    class Meta:
        app_label = 'lk'
        unique_together = (
            'app',
            'unique_id',
        )

    ENCRYPTED_ID_KEY_TOKEN = 'sdk-user'

    user = models.ForeignKey(User,
                             related_name='+',
                             on_delete=models.DO_NOTHING)
    app = models.ForeignKey(SDKApp,
                            related_name='+',
                            on_delete=models.DO_NOTHING)

    create_time = models.DateTimeField(auto_now_add=True)
    last_accessed_time = models.DateTimeField(auto_now_add=True)

    unique_id = models.CharField(max_length=128, null=True)
    name = models.CharField(max_length=128, null=True)
    email = models.CharField(max_length=128, null=True)

    screens = models.PositiveIntegerField(default=0)
    taps = models.PositiveIntegerField(default=0)
    visits = models.PositiveIntegerField(default=0)
    seconds = models.PositiveIntegerField(default=0)

    days_active_map = models.BigIntegerField(default=0)

    monthly_screens = models.PositiveIntegerField(default=0)
    monthly_taps = models.PositiveIntegerField(default=0)
    monthly_visits = models.PositiveIntegerField(default=0)
    monthly_seconds = models.PositiveIntegerField(default=0)
    monthly_days_active = models.PositiveIntegerField(default=0)

    labels = TextArrayField(null=True)
    data = hstore_field.HStoreField(null=True)

    def is_anonymous(self):
        return not (self.unique_id or self.name or self.email)

    @property
    def monthly_days_active_computed(self):
        return bitwise.num_bits_64(self.last_month_active_bitmap())

    def last_month_active_bitmap(self, now_days_offset=0):
        offset = self.days_active_bitmap_offset_for_date(
            now_days_offset=now_days_offset)
        # This is DAYS_IN_MONTH - 1 here because today is bit 0.
        shift = offset - (DAYS_IN_MONTH - 1)
        days_active_map = (self.days_active_map or 0) & bitwise.BITS_64
        shifted_map = bitwise.wrapping_right_shift_64(days_active_map, shift)
        return shifted_map & bitwise.flipped_bits_64(DAYS_IN_MONTH)

    def weekly_days_active(self, now_days_offset=0):
        return bitwise.num_bits_64(
            self.weekly_days_active_bitmap(now_days_offset=now_days_offset))

    def weekly_days_active_bitmap(self, now_days_offset=0):
        return self.last_month_active_bitmap_reversed(
            now_days_offset=now_days_offset) & 0b1111111

    def last_month_active_bitmap_reversed(self, now_days_offset=0):
        # You will get a DAYS_IN_MONTH-long bitmap, shifted so that:
        # today is (map & 1), yest. is (map & (1 << 1)), 2d ago is (map & (1 << 2))
        return bitwise.reverse_bits(
            self.last_month_active_bitmap(now_days_offset=now_days_offset),
            DAYS_IN_MONTH)

    def days_active_bitmap_offset_for_date(self,
                                           now_date=None,
                                           now_days_offset=0):
        if now_date is None:
            now_date = datetime.now().date()
            if now_days_offset is not None:
                now_date += timedelta(days=now_days_offset)

        return (now_date - self.create_time.date()).days % 64

    def days_active_bitmap_valid_bitmask(self, now_days_offset=0):
        # By default, this is tomorrow's offset.
        offset = self.days_active_bitmap_offset_for_date(
            now_days_offset=(1 + now_days_offset))
        return bitwise.trailing_window_bitmask_64(offset, DAYS_IN_MONTH)

    @property
    def filtered_labels(self):
        if not self.labels:
            return []

        labels = []
        for label in ['super', 'almost', 'fringe']:
            if label in self.labels:
                labels.append(label)
        if 'active-1m' in self.labels:
            labels.append('active')
        else:
            labels.append('inactive')

        return labels

    def to_client_dict(self):
        return {
            'name': self.name,
            'uniqueId': self.unique_id,
            'email': self.email,
            'firstVisit': self.date_to_api_date(self.create_time),
            'stats': {
                'visits': self.monthly_visits,
                'days': self.monthly_days_active_computed,
            },
            'labels': self.filtered_labels,
        }

    def to_dict(self, include_raw_labels=False):
        user = {
            'id': self.encrypted_id,
            'appId': SDKApp.encrypt_id(self.app_id),
            'name': self.name,
            'uniqueId': self.unique_id,
            'email': self.email,
            'latestVisit': self.date_to_api_date(self.last_accessed_time),
            'firstVisit': self.date_to_api_date(self.create_time),
            'stats': {
                'screens': self.monthly_screens,
                'taps': self.monthly_taps,
                'visits': self.monthly_visits,
                'seconds': self.monthly_seconds,
                'days': self.monthly_days_active_computed,
            },
            'labels': self.filtered_labels,
        }

        if include_raw_labels:
            user['rawLabels'] = self.labels

        return user
Esempio n. 14
0
class SDKUserIncrementLog(APIModel):
    sdk_user = models.ForeignKey(SDKUser, on_delete=models.DO_NOTHING)
    create_time = models.DateTimeField()
    data = hstore_field.HStoreField(null=True)
Esempio n. 15
0
class AppStoreAppInfo(APIModel):
    create_time = models.DateTimeField(auto_now_add=True)

    app = models.ForeignKey(AppStoreApp,
                            related_name='+',
                            db_index=False,
                            on_delete=models.DO_NOTHING)

    data = hstore_field.HStoreField()

    itunes_id = data.long_property()
    bundle_id = data.string_property()

    mac_software = data.bool_property()

    name = data.string_property()
    description = data.string_property()
    release_notes = data.string_property()

    version = data.string_property()

    icon_60 = data.string_property()
    icon_100 = data.string_property()
    icon_512 = data.string_property()

    category = data.int_property()

    price = data.float_property()
    currency = data.string_property()

    size_bytes = data.long_property()

    rating = data.float_property()
    reviews_count = data.int_property()

    current_version_rating = data.float_property()
    current_version_reviews_count = data.int_property()

    content_rating = data.string_property()  # 4+, etc.

    developer_id = data.long_property()
    developer_url = data.string_property()
    developer_name = data.string_property()

    categories = IntegerArrayField()
    screenshots = TextArrayField()
    ipad_screenshots = TextArrayField(null=True)

    release_date = models.DateTimeField()

    country = models.CharField(null=True, max_length=2)

    @property
    def short_name(self):
        return text.app_short_name(self.name)

    def to_tiny_dict(self):
        return {
            'iTunesId': self.itunes_id,
            'name': self.name,
            'icon': {
                'small': self.icon_60,
            },
            'developer': {
                'id': self.developer_id,
                'name': self.developer_name,
            },
        }

    def to_dict(self):
        full_dict = self.to_tiny_dict()

        full_dict['bundleId'] = self.bundle_id

        full_dict['version'] = self.version
        full_dict['category'] = self.category
        full_dict['description'] = self.description
        full_dict['icon']['medium'] = self.icon_100
        full_dict['icon']['large'] = self.icon_512

        full_dict['developer']['url'] = self.developer_url

        full_dict['rating'] = self.rating
        full_dict['reviewCount'] = self.reviews_count
        full_dict['currentRating'] = self.current_version_rating
        full_dict['currentRatingStars'] = ''.join(
            [u'★'] * int(self.current_version_rating))
        full_dict['currentReviewCount'] = self.current_version_reviews_count

        full_dict['screenshots'] = self.screenshots

        return full_dict
Esempio n. 16
0
class SDKApp(APIModel):
    class Meta:
        app_label = 'lk'
        unique_together = (
            'user',
            'bundle_id',
        )

    ENCRYPTED_ID_KEY_TOKEN = 'sdk-app'

    user = models.ForeignKey(User,
                             related_name='+',
                             on_delete=models.DO_NOTHING)
    create_time = models.DateTimeField(auto_now_add=True)
    update_time = models.DateTimeField(auto_now=True)
    latest_track_time = models.DateTimeField(null=True)

    display_name = models.CharField(max_length=128, null=True)
    bundle_id = models.CharField(max_length=128, null=False)

    latest_debug_version = models.CharField(max_length=24, null=True)
    latest_prod_version = models.CharField(max_length=24, null=True)

    appstore_app = models.ForeignKey(AppStoreApp,
                                     null=True,
                                     related_name='+',
                                     on_delete=models.DO_NOTHING)
    appstore_app_country = models.CharField(max_length=2, null=True)

    super_config = TextArrayField(default=_default_super_config, null=False)
    almost_config = TextArrayField(default=_default_almost_config, null=False)

    config_parent = models.ForeignKey('self',
                                      null=True,
                                      related_name='config_children',
                                      on_delete=models.DO_NOTHING)

    products = hstore_field.HStoreField(null=True)
    config = products.bool_property()
    super_users = products.bool_property()

    # Decorated properties.

    decorated_label_counts = None
    decorated_config_children = None

    @property
    def name(self):
        if self.display_name:
            return self.display_name
        if self.appstore_app:
            return self.appstore_app.name
        return self.bundle_id

    @property
    def short_name(self):
        return text.app_short_name(self.name)

    def to_dict(self):
        products = [p for p in (self.products or {}) if getattr(self, p)]

        app = {
            'id': self.encrypted_id,
            'bundleId': self.bundle_id,
            'iTunesId': self.appstore_app and self.appstore_app.itunes_id,
            'names': {
                'short': self.short_name,
                'full': self.name,
                'display': self.display_name,
            },
            'icons': {
                'small':
                self.appstore_app and self.appstore_app.public_small_icon,
                'medium':
                self.appstore_app and self.appstore_app.public_medium_icon,
            },
            'latestTrackTime': self.date_to_api_date(self.latest_track_time),
            'latestVersion': {
                'debug': self.latest_debug_version,
                'prod': self.latest_prod_version,
            },
            'products': products,
        }

        if self.super_users:
            super_freq, super_time = self.super_config
            app['super'] = {
                'freq': super_freq,
                'time': super_time,
            }

        if self.decorated_label_counts is not None:
            # Return a simplified list here.
            app['stats'] = {
                'active': self.decorated_label_counts.get('active-1m', 0),
                'inactive': self.decorated_label_counts.get('inactive-1m', 0),
            }
            if self.super_users:
                app['stats']['super'] = self.decorated_label_counts.get(
                    'super', 0)
                app['stats']['almost'] = self.decorated_label_counts.get(
                    'almost', 0)
                app['stats']['fringe'] = self.decorated_label_counts.get(
                    'fringe', 0)

        if self.decorated_config_children:
            app['configChildren'] = [
                a.to_dict() for a in self.decorated_config_children
            ]
        elif self.config_parent_id:
            app['configChild'] = True

        return app
Esempio n. 17
0
class AppWebsite(APIModel):
  PLATFORMS = ['iPhone']
  ENCRYPTED_ID_KEY_TOKEN = 'appwebsites'

  domain = models.CharField(max_length=100, unique=True, null=True)

  user = models.ForeignKey(User, related_name='+', on_delete=models.DO_NOTHING)

  logo = models.ForeignKey(Image, related_name='+', null=True, on_delete=models.DO_NOTHING)
  background = models.ForeignKey(Image, related_name='+', null=True, on_delete=models.DO_NOTHING)
  icon = models.ForeignKey(Image, related_name='+', null=True, on_delete=models.DO_NOTHING)

  create_time = models.DateTimeField(auto_now_add=True, db_index=True)
  update_time = models.DateTimeField(auto_now=True)
  delete_time = models.DateTimeField(null=True, default=None)

  data = hstore_field.HStoreField(null=True)

  template = data.string_property()

  app_name = data.string_property()
  tagline = data.string_property()

  short_description = data.string_property()
  long_description = data.string_property()
  keywords = data.string_property()
  google_analytics_id = data.string_property()

  itunes_id = data.string_property()
  play_store_id = data.string_property()
  waiting_list_link = data.string_property()
  waiting_list_label = data.string_property()

  itunes_campaign_token = data.string_property()
  itunes_provider_token = data.string_property()

  support_link = data.string_property()
  blog_link = data.string_property()
  login_link = data.string_property()
  press_link = data.string_property()
  terms_link = data.string_property()
  privacy_link = data.string_property()
  twitter_link = data.string_property()
  facebook_link = data.string_property()
  instagram_link = data.string_property()
  custom_link = data.string_property()
  custom_link_label = data.string_property()

  disable_lk_branding = data.bool_property()
  mixpanel_badge = data.bool_property()

  terms_text = data.string_property()
  privacy_text = data.string_property()
  support_text = data.string_property()

  primary_color = data.string_property()
  font = data.string_property()
  frame_screenshots = data.string_property()

  custom_css = data.string_property()

  def to_dict(self, include_pages=False):
    screenshots = list(
      self.screenshots
          .select_related('image')
          .order_by('order')
    )

    screenshots_by_platform = {p: [] for p in self.PLATFORMS}
    for screenshot in screenshots:
      screenshots_by_platform[screenshot.platform].append(screenshot.to_dict())

    images = {
      'screenshots': screenshots_by_platform,
    }

    if self.icon:
      images['icon'] = {'id': self.icon.encrypted_id, 'url': self.icon.gae_image_url}
    if self.logo:
      images['logo'] = {'id': self.logo.encrypted_id, 'url': self.logo.gae_image_url}
    if self.background:
      images['background'] = {'id': self.background.encrypted_id, 'url': self.background.gae_image_url}

    website_data = {
      'id': self.encrypted_id,
      'domain': self.domain,
      'googleAnalyticsId': self.google_analytics_id,
      'template': self.template,
      'appName': self.app_name,
      'tagline': self.tagline,
      'shortDescription': self.short_description,
      'longDescription': self.long_description,
      'keywords': self.keywords,
      'author': self.user.full_name,
      'itunesId': self.itunes_id,
      'playStoreId': self.play_store_id,
      'waitingListLink': self.waiting_list_link,
      'waitingListLabel': self.waiting_list_label,
      'itunesCampaignToken': self.itunes_campaign_token,
      'itunesProviderToken': self.itunes_provider_token,
      'supportLink': self.support_link,
      'blogLink': self.blog_link,
      'loginLink': self.login_link,
      'pressLink': self.press_link,
      'termsLink': self.terms_link,
      'privacyLink': self.privacy_link,
      'twitterLink': self.twitter_link,
      'facebookLink': self.facebook_link,
      'instagramLink': self.instagram_link,
      'customLink': self.custom_link,
      'customLinkLabel': self.custom_link_label,
      'primaryColor': self.primary_color,
      'font': self.font,
      'disableLkBranding': self.disable_lk_branding,
      'mixpanelBadge': self.mixpanel_badge,
      'frameScreenshots': self.frame_screenshots,
      'images': images,
      'customCss': self.custom_css
    }


    pages = AppWebsitePage.objects.filter(website=self.id)
    for page in pages:
      if include_pages:
        website_data[page.slug] = page.body
      elif page.body:
        website_data[page.slug] = True

    return website_data

  @property
  def public_page_link(self):
    return '%swebsites/dashboard/%s/public/' % (settings.SITE_URL, self.encrypted_id)
class Image(APIModel):
    ENCRYPTED_ID_KEY_TOKEN = 'image'

    kind = models.CharField(max_length=32, null=True)

    user = models.ForeignKey(User,
                             related_name='+',
                             null=True,
                             on_delete=models.DO_NOTHING)

    create_time = models.DateTimeField(auto_now_add=True)
    update_time = models.DateTimeField(auto_now=True)

    ref_count = models.PositiveIntegerField(default=0)
    deleted = models.BooleanField(default=False)

    time_taken = models.DateTimeField(null=True)

    data = hstore_field.HStoreField(null=True)

    location_latitude = data.float_property()
    location_longitude = data.float_property()

    gae_image_url = data.string_property()

    format = data.string_property()
    width = data.int_property()
    height = data.int_property()
    size_bytes = data.int_property()

    def increment_ref_count(self):
        Image.objects.filter(id=self.id).update(ref_count=F('ref_count') + 1)
        self.ref_count += 1

    def decrement_ref_count(self):
        Image.objects.filter(id=self.id).update(ref_count=F('ref_count') - 1)
        self.ref_count -= 1

    @property
    def extension(self):
        # TODO(Taylor): jpeg to jpg? etc.
        return self.format

    def image_url(self, width=None, height=None, quality=0):
        args = []
        if width is None and height is None:
            args.append('s0')
        else:
            if width:
                args.append('w%d' % width)
            if height:
                args.append('h%d' % height)
            if width and height:
                # crop the image rather than making it tiny
                args.append('c')
            if quality:
                # quality should be 0-100
                args.append('q%d' % quality)
        #return self.gae_image_url + '=%s' % '-'.join(args)
        self.gae_image_url + '=%s' % '-'.join(args)
        self.gae_image_url = self.gae_image_url.replace(
            "localhost", "192.168.0.100")
        return self.gae_image_url

    def to_dict(self):
        return {
            'id': self.encrypted_id,
            'width': self.width,
            'height': self.height,
            'imageUrls': {
                'small': self.image_url(width=200),
                'medium': self.image_url(width=640),
                'full': self.image_url(),
            }
        }
Esempio n. 19
0
class AppStoreReviewSubscription(APIModel):
    ENCRYPTED_ID_KEY_TOKEN = 'appstore-review-sub'

    create_time = models.DateTimeField(auto_now_add=True)
    update_time = models.DateTimeField(auto_now=True)

    user = models.ForeignKey(User,
                             related_name='+',
                             on_delete=models.DO_NOTHING)
    enabled = models.BooleanField(default=False)
    invalidated_time = models.DateTimeField(null=True)

    last_notification_time = models.DateTimeField(null=True)

    twitter_connection = models.OneToOneField(TwitterAppConnection,
                                              related_name='subscription',
                                              null=True)

    data = hstore_field.HStoreField(null=True)

    email = data.string_property()
    my_email = data.bool_property()
    slack_url = data.string_property()

    slack_channel_id = data.string_property()
    slack_channel_name = data.string_property()

    filter_good = data.bool_property()
    filter_very_good = data.bool_property()
    filter_app = models.ForeignKey(AppStoreApp,
                                   related_name='+',
                                   null=True,
                                   on_delete=models.DO_NOTHING)

    def to_dict(self):
        d = {
            'id':
            self.encrypted_id,
            'createTime':
            self.date_to_api_date(self.create_time),
            'lastNotificationTime':
            self.date_to_api_date(self.last_notification_time),
            'filter': {},
        }
        if self.email:
            d['email'] = self.email
        if self.my_email:
            d['myEmail'] = True
        if self.slack_url:
            d['slackUrl'] = self.slack_url
        if self.slack_channel_name:
            d['slackChannel'] = {'name': self.slack_channel_name}
        if self.twitter_connection_id:
            d['twitterHandle'] = self.twitter_connection.handle
        if self.filter_good:
            d['filter']['good'] = True
        if self.filter_very_good:
            d['filter']['veryGood'] = True
        if self.filter_app_id:
            d['filter']['app'] = self.filter_app.to_dict()
        return d