def __init__(self, name): self.name = name.lower().strip().replace('#', '') self.base_key = 'tag:{}:posts'.format(self.name) self.new = RedisSortedSet(self.base_key) self.images_only = RedisLastBumpedBuffer(self.base_key + ':images', 1000) self.popular = RedisLastBumpedBuffer(self.base_key + ':popular', 1000) self.post_count = RedisKey(self.base_key + ':count')
def _record(timestamp_key): if request: RedisSet(timestamp_key + ":unique_ips").sadd( util.ip_to_int(request.META.get('REMOTE_ADDR'))) if user: RedisSet(timestamp_key + ":uniques").sadd(user.id) RedisKey(timestamp_key + ":count").incr(1)
def __init__(self, type_id, name="", value=None, preference=None, limited=False, hidden=False, unusable=False, cost=None, title="", shop_filename=None, shop_text="", purchasable=None, achievement=None, admin_only=False, maximum=None, hide_from_inventory=False, seasonal=False): """ admin: Whether this sticker is only available for admins. shop_filename: Defaults to "name.png" if unspecified here. purchasable: Leave this as `None` and it will be determined from the cost and achievement status. Set it to `False` to override this and force it to not be sold in the shop. """ if cost is not None: cost = int(cost) if value is None: if cost is None or cost < 1: value = 1 else: value = math.sqrt(cost+1) else: value = float(value) self._purchasable = purchasable if purchasable and not cost: raise ValueError('A sticker without a cost cannot be purchasable.') if shop_filename is None: shop_filename = u'{0}.png'.format(name) self.type_id = type_id self.name = name self.value = value self.preference = preference if preference is not None else type_id self._is_limited = bool(limited or cost or maximum) # not placeable anymore, but should still show up on existing posts. self._is_unusable = unusable # not placeable anymore nor should it show up on already stickered posts. self.is_hidden = hidden self.cost = cost self.title = title self.shop_filename = shop_filename self.shop_text = shop_text self.achievement = achievement self.admin_only = admin_only self.maximum = maximum self.user_remaining = None self.inventory_hash = None if self.maximum: self.inventory_hash = RedisKey("sticker:%s:remaining" % self.name) self.seasonal = seasonal self.hide_from_inventory = hide_from_inventory
def branch_count(self, experiment_name, branch_name): return int( RedisKey(self.basekey + ":" + "experiment:%s:%s:count" % (experiment_name, branch_name)).get() or 0)
def hourly_count(self, datetime): return int( RedisKey(self.basekey + ":" + datetime.strftime("%Y.%m.%d.%H") + ":count").get() or 0)
def daily_count(self, day): return int(RedisKey(self.daykey(day, 'count')).get() or 0)
def timestamp_key(self): return RedisKey(self.basekey + ":last_timestamp")
class Tag(object): top = property(lambda self: DateKey(lambda key: RedisLastBumpedBuffer(key, 30*30), self.base_key, ':top')) updates_channel = property(lambda self: RealtimeChannel('tu:%s' % self.name, 5, ttl=24*60*60)) def __repr__(self): return self.name def __init__(self, name): self.name = name.lower().strip().replace('#', '') self.base_key = 'tag:{}:posts'.format(self.name) self.new = RedisSortedSet(self.base_key) self.images_only = RedisLastBumpedBuffer(self.base_key + ':images', 1000) self.popular = RedisLastBumpedBuffer(self.base_key + ':popular', 1000) self.post_count = RedisKey(self.base_key + ':count') def to_client(self, **kwargs): return self.name def tag_comment(self, comment, timestamp=None): if timestamp is None: timestamp = Services.time.time() self.new.zadd(int(comment.id), timestamp) all_tags.sadd(self.name) if comment.reply_content is not None: self.images_only.bump(int(comment.id), score=timestamp) count = self.post_count.incr() self.updates_channel.publish({'post': comment.id, 'tag': self.name, 'count': count}) def untag_comment(self, comment): self.new.zrem(comment.id) self.images_only.remove(comment.id) self.popular.remove(comment.id) def get_absolute_url(self): return '/x/' + self.name.replace('#','') def user_is_following(self, user): if not user.is_authenticated(): return False return self.name in user.redis.followed_tags def merge_top_scores(self, day=None): """ Merges daily top scores into monthly and monthly into yearly top scores for this group for the given day and the 365 days before it. If `day` is `None`, defaults to today. """ if not day: day = Services.time.today() # Merge today + last 365 days days = [day - datetime.timedelta(n) for n in range(366)] months = defaultdict(list) for day in days: months[(day.year, day.month)].append(day) years = defaultdict(list) for (year, month) in months.keys(): years[year].append(month) for (year, month), days in months.iteritems(): dest = self.top.month(datetime.date(year, month, 1)) source_keys = [self.top.day(day).key for day in days] redis.zunionstore(dest.key, source_keys, aggregate='max') dest.truncate(2) for year, year_months in years.iteritems(): dest = self.top.year(datetime.date(year, 1, 1)) source_keys = [self.top.month(datetime.date(year, month, 1)).key for month in year_months] redis.zunionstore(dest.key, source_keys, aggregate='max') dest.truncate(5)
class Sticker(object): """ A datastructure to hold a Canvas sticker definition. Note that the `details` property (and `to_client()`) never gets updated after instantiation. """ def __eq__(self, another_sticker): try: return self.type_id == another_sticker.type_id except AttributeError: return False def __init__(self, type_id, name="", value=None, preference=None, limited=False, hidden=False, unusable=False, cost=None, title="", shop_filename=None, shop_text="", purchasable=None, achievement=None, admin_only=False, maximum=None, hide_from_inventory=False, seasonal=False): """ admin: Whether this sticker is only available for admins. shop_filename: Defaults to "name.png" if unspecified here. purchasable: Leave this as `None` and it will be determined from the cost and achievement status. Set it to `False` to override this and force it to not be sold in the shop. """ if cost is not None: cost = int(cost) if value is None: if cost is None or cost < 1: value = 1 else: value = math.sqrt(cost+1) else: value = float(value) self._purchasable = purchasable if purchasable and not cost: raise ValueError('A sticker without a cost cannot be purchasable.') if shop_filename is None: shop_filename = u'{0}.png'.format(name) self.type_id = type_id self.name = name self.value = value self.preference = preference if preference is not None else type_id self._is_limited = bool(limited or cost or maximum) # not placeable anymore, but should still show up on existing posts. self._is_unusable = unusable # not placeable anymore nor should it show up on already stickered posts. self.is_hidden = hidden self.cost = cost self.title = title self.shop_filename = shop_filename self.shop_text = shop_text self.achievement = achievement self.admin_only = admin_only self.maximum = maximum self.user_remaining = None self.inventory_hash = None if self.maximum: self.inventory_hash = RedisKey("sticker:%s:remaining" % self.name) self.seasonal = seasonal self.hide_from_inventory = hide_from_inventory @property def active_seasonal(self): return self in get_active_seasonal_stickers() @property def is_unusable(self): if self.seasonal: return not self.active_seasonal else: return self._is_unusable @property def is_limited(self): if self.seasonal: return self.active_seasonal else: return self._is_limited def is_epic(self): """ Recipients of Epic stickers get an exciting realtime notification. """ return self.cost >= knobs.EPIC_STICKER_COST_THRESHOLD def is_star(self): from django.conf import settings if not hasattr(settings, 'STAR_STICKER_TYPE_ID'): return False return self.type_id == settings.STAR_STICKER_TYPE_ID def is_usable(self, user): """ Whether this sticker can be used by the user. Takes several factors into account, not just `Sticker.is_unusable`. """ return bool(self.cost and not self.is_unusable and not self.is_hidden and (self.achievement is None or user.kv.achievements.by_id(self.achievement).get())) def is_limited_inventory(self): """ Whether this sticker has a limited number of units available. """ return self.maximum != None def is_purchasable(self, user): if self._purchasable is None: if self.is_limited_inventory() and self.is_out_of_stock(): # Then it can be purchased if there are enough. # Note that we do not check for whether the user has already bought the # sticker here. We also do not check if the user can afford it. # This logic is done in api.store_buy return False return bool(self.cost and (self.achievement is None or user.kv.achievements.by_id(self.achievement).get())) return self._purchasable @property def remaining(self): """ Returns the number of stickers available. """ if self.inventory_hash: # Was the value ever bootstrapped if self.inventory_hash.get() == None: self.inventory_hash.set(self.maximum) return int(self.inventory_hash.get()) return None def is_out_of_stock(self): return self.remaining == 0 def decrement_inventory(self): try: return int(self.inventory_hash.decr()) except: pass def to_client(self): keys = [ 'type_id', 'name', 'value', 'preference', 'is_limited', 'is_unusable', 'is_hidden', 'cost', 'title', 'shop_filename', 'shop_text', 'achievement', 'admin_only', 'maximum', 'user_remaining', ] return dict([(key, getattr(self, key)) for key in keys]) def sort_key(self, count): score = count * (self.cost+1 if self.cost else 1) return (score, int(self.is_limited), self.preference) def __repr__(self): return unicode(self.to_client())
def __init__(self, type_id, name="", value=None, preference=None, limited=False, hidden=False, unusable=False, cost=None, title="", shop_filename=None, shop_text="", purchasable=None, achievement=None, admin_only=False, maximum=None, hide_from_inventory=False, seasonal=False): """ admin: Whether this sticker is only available for admins. shop_filename: Defaults to "name.png" if unspecified here. purchasable: Leave this as `None` and it will be determined from the cost and achievement status. Set it to `False` to override this and force it to not be sold in the shop. """ if cost is not None: cost = int(cost) if value is None: if cost is None or cost < 1: value = 1 else: value = math.sqrt(cost + 1) else: value = float(value) self._purchasable = purchasable if purchasable and not cost: raise ValueError('A sticker without a cost cannot be purchasable.') if shop_filename is None: shop_filename = u'{0}.png'.format(name) self.type_id = type_id self.name = name self.value = value self.preference = preference if preference is not None else type_id self._is_limited = bool(limited or cost or maximum) # not placeable anymore, but should still show up on existing posts. self._is_unusable = unusable # not placeable anymore nor should it show up on already stickered posts. self.is_hidden = hidden self.cost = cost self.title = title self.shop_filename = shop_filename self.shop_text = shop_text self.achievement = achievement self.admin_only = admin_only self.maximum = maximum self.user_remaining = None self.inventory_hash = None if self.maximum: self.inventory_hash = RedisKey("sticker:%s:remaining" % self.name) self.seasonal = seasonal self.hide_from_inventory = hide_from_inventory
class Sticker(object): """ A datastructure to hold a Canvas sticker definition. Note that the `details` property (and `to_client()`) never gets updated after instantiation. """ def __eq__(self, another_sticker): try: return self.type_id == another_sticker.type_id except AttributeError: return False def __init__(self, type_id, name="", value=None, preference=None, limited=False, hidden=False, unusable=False, cost=None, title="", shop_filename=None, shop_text="", purchasable=None, achievement=None, admin_only=False, maximum=None, hide_from_inventory=False, seasonal=False): """ admin: Whether this sticker is only available for admins. shop_filename: Defaults to "name.png" if unspecified here. purchasable: Leave this as `None` and it will be determined from the cost and achievement status. Set it to `False` to override this and force it to not be sold in the shop. """ if cost is not None: cost = int(cost) if value is None: if cost is None or cost < 1: value = 1 else: value = math.sqrt(cost + 1) else: value = float(value) self._purchasable = purchasable if purchasable and not cost: raise ValueError('A sticker without a cost cannot be purchasable.') if shop_filename is None: shop_filename = u'{0}.png'.format(name) self.type_id = type_id self.name = name self.value = value self.preference = preference if preference is not None else type_id self._is_limited = bool(limited or cost or maximum) # not placeable anymore, but should still show up on existing posts. self._is_unusable = unusable # not placeable anymore nor should it show up on already stickered posts. self.is_hidden = hidden self.cost = cost self.title = title self.shop_filename = shop_filename self.shop_text = shop_text self.achievement = achievement self.admin_only = admin_only self.maximum = maximum self.user_remaining = None self.inventory_hash = None if self.maximum: self.inventory_hash = RedisKey("sticker:%s:remaining" % self.name) self.seasonal = seasonal self.hide_from_inventory = hide_from_inventory @property def active_seasonal(self): return self in get_active_seasonal_stickers() @property def is_unusable(self): if self.seasonal: return not self.active_seasonal else: return self._is_unusable @property def is_limited(self): if self.seasonal: return self.active_seasonal else: return self._is_limited def is_epic(self): """ Recipients of Epic stickers get an exciting realtime notification. """ return self.cost >= knobs.EPIC_STICKER_COST_THRESHOLD def is_star(self): from django.conf import settings if not hasattr(settings, 'STAR_STICKER_TYPE_ID'): return False return self.type_id == settings.STAR_STICKER_TYPE_ID def is_usable(self, user): """ Whether this sticker can be used by the user. Takes several factors into account, not just `Sticker.is_unusable`. """ return bool(self.cost and not self.is_unusable and not self.is_hidden and (self.achievement is None or user.kv.achievements.by_id(self.achievement).get())) def is_limited_inventory(self): """ Whether this sticker has a limited number of units available. """ return self.maximum != None def is_purchasable(self, user): if self._purchasable is None: if self.is_limited_inventory() and self.is_out_of_stock(): # Then it can be purchased if there are enough. # Note that we do not check for whether the user has already bought the # sticker here. We also do not check if the user can afford it. # This logic is done in api.store_buy return False return bool( self.cost and (self.achievement is None or user.kv.achievements.by_id(self.achievement).get())) return self._purchasable @property def remaining(self): """ Returns the number of stickers available. """ if self.inventory_hash: # Was the value ever bootstrapped if self.inventory_hash.get() == None: self.inventory_hash.set(self.maximum) return int(self.inventory_hash.get()) return None def is_out_of_stock(self): return self.remaining == 0 def decrement_inventory(self): try: return int(self.inventory_hash.decr()) except: pass def to_client(self, **kwargs): keys = [ 'type_id', 'name', 'value', 'preference', 'is_limited', 'is_unusable', 'is_hidden', 'cost', 'title', 'shop_filename', 'shop_text', 'achievement', 'admin_only', 'maximum', 'user_remaining', ] return dict([(key, getattr(self, key)) for key in keys]) def sort_key(self, count): score = count * (self.cost + 1 if self.cost else 1) return (score, int(self.is_limited), self.preference) def __repr__(self): return unicode(self.to_client())
class Tag(object): top = property(lambda self: DateKey(lambda key: RedisLastBumpedBuffer(key, 30*30), self.base_key, ':top')) updates_channel = property(lambda self: RealtimeChannel('tu:%s' % self.name, 5, ttl=24*60*60)) def __repr__(self): return self.name def __init__(self, name): self.name = name.lower().strip().replace('#', '') self.base_key = 'tag:{}:posts'.format(self.name) self.new = RedisSortedSet(self.base_key) self.images_only = RedisLastBumpedBuffer(self.base_key + ':images', 1000) self.popular = RedisLastBumpedBuffer(self.base_key + ':popular', 1000) self.post_count = RedisKey(self.base_key + ':count') def to_client(self): return self.name def tag_comment(self, comment, timestamp=None): if timestamp is None: timestamp = Services.time.time() self.new.zadd(int(comment.id), timestamp) all_tags.sadd(self.name) if comment.reply_content is not None: self.images_only.bump(int(comment.id), score=timestamp) count = self.post_count.incr() self.updates_channel.publish({'post': comment.id, 'tag': self.name, 'count': count}) def untag_comment(self, comment): self.new.zrem(comment.id) self.images_only.remove(comment.id) self.popular.remove(comment.id) def get_absolute_url(self): return '/x/' + self.name.replace('#','') def user_is_following(self, user): if not user.is_authenticated(): return False return self.name in user.redis.followed_tags def merge_top_scores(self, day=None): """ Merges daily top scores into monthly and monthly into yearly top scores for this group for the given day and the 365 days before it. If `day` is `None`, defaults to today. """ if not day: day = Services.time.today() # Merge today + last 365 days days = [day - datetime.timedelta(n) for n in range(366)] months = defaultdict(list) for day in days: months[(day.year, day.month)].append(day) years = defaultdict(list) for (year, month) in months.keys(): years[year].append(month) for (year, month), days in months.iteritems(): dest = self.top.month(datetime.date(year, month, 1)) source_keys = [self.top.day(day).key for day in days] redis.zunionstore(dest.key, source_keys, aggregate='max') dest.truncate(2) for year, year_months in years.iteritems(): dest = self.top.year(datetime.date(year, 1, 1)) source_keys = [self.top.month(datetime.date(year, month, 1)).key for month in year_months] redis.zunionstore(dest.key, source_keys, aggregate='max') dest.truncate(5)