class SmartCategory(SmartObject): UPLOAD_TO = 'commarketing/smart_categories' image = MultiImageField(upload_to=UPLOAD_TO, blank=True, null=True, max_size=500) description = models.TextField(blank=True, help_text=_("Description of the category.")) badge_text = models.CharField( max_length=25, blank=True, help_text=_("Text in the badge that appears on the smart category. " "<strong>E.g.:</strong> -20%, -30%, New, etc.")) appear_in_menu = models.BooleanField( default=False, help_text=_("Smart Category will appear in main menu if checked.")) show_on_home = models.BooleanField( _("Show on home ?"), default=True, help_text=_( "Check to show a preview of items contained on home page.")) def _get_module(self): try: return Module.objects.get(slug=self.slug) except: pass module = property(_get_module)
class SmartCategory(SmartObject): UPLOAD_TO = 'web/smart_categories' content_type = models.CharField( max_length=15, choices=SMART_CATEGORY_TYPE_CHOICES, help_text=_("Whether this menu points to a page, a list of items.")) image = MultiImageField(upload_to=UPLOAD_TO, blank=True, null=True, max_size=500) description = models.TextField(blank=True, help_text=_("Description of the category.")) badge_text = models.CharField( max_length=25, blank=True, help_text=_("Text in the badge that appears on the smart category. " "<strong>E.g.:</strong> -20%, -30%, New, etc.")) appear_in_menu = models.BooleanField( default=False, help_text=_("Smart Category will appear in main menu if checked.")) target_url = models.URLField(blank=True) def _get_module(self): try: return Module.objects.get(slug=self.slug) except: pass module = property(_get_module)
class AbstractProduct(Model): """ Abstract definition of product a customer may subscribe to """ IMAGE_UPLOAD_TO = 'billing/product_images' name = models.CharField( max_length=100, unique=True, db_index=True, help_text="Name of the product as advertised to the customer.") slug = models.SlugField(unique=True, db_index=True) short_description = models.TextField( blank=True, help_text=_("Short description understandable by the customer.")) duration = models.IntegerField( default=30, help_text="Number of days covered by the cost this product.") duration_text = models.CharField( max_length=30, blank=True, null=True, help_text=_( "How you want the customer to see the duration.<br>" "Eg:<strong>1 month</strong>, <strong>3 months</strong>, etc.")) cost = models.FloatField( help_text=_("Cost of the product on the duration set previously.")) image = MultiImageField(upload_to=IMAGE_UPLOAD_TO, blank=True, null=True, max_size=800) details = models.TextField( blank=True, help_text=_("Detailed description of the product.")) is_active = models.BooleanField( default=True, help_text=_("Check to make the product active.")) is_main = models.BooleanField( default=False, help_text=_("Check to make the product active.")) is_one_off = models.BooleanField( default=False, help_text=_("One off product generates a one off subscription.")) order_of_appearance = models.IntegerField(default=1) class Meta: abstract = True def __unicode__(self): from ikwen.core.utils import get_service_instance config = get_service_instance().config return u'%s: %s %.2f/%d days' % (self.name, config.currency_symbol, self.cost, self.duration) def get_details(self): if not self.details: return 'N/A' return self.details
class Album(AbstractWatchModel): artist = models.ForeignKey(Artist) title = models.CharField(max_length=100, db_index=True) slug = models.SlugField(db_index=True) cover = MultiImageField(upload_to='albums_covers', required_width=300, required_height=300, allowed_extensions=['jpg', 'jpeg'], blank=True, null=True, help_text=_("JPEG Image, 300 × 300px")) release = models.DateField(blank=True, null=True, db_index=True) archive = FileField(upload_to='albums_covers', allowed_extensions=['zip', 'rar', '7z'], blank=True, null=True) cost = models.IntegerField(default=0) is_active = models.BooleanField(default=True) is_main = models.BooleanField(default=False) show_on_home = models.BooleanField(default=False) order_of_appearance = models.IntegerField(default=0) tags = models.TextField(blank=True, null=True) turnover_history = ListField() earnings_history = ListField() units_sold_history = ListField() total_turnover = models.IntegerField(default=0) total_earnings = models.IntegerField(default=0) total_units_sold = models.IntegerField(default=0) class Meta: unique_together = ('artist', 'title') def __unicode__(self): return "%s - %s (%d)" % (self.artist.name, self.title, self.release.year) def _get_image(self): return self.cover image = property(_get_image) def get_obj_details(self): return "XAF %s" % intcomma(self.cost) def to_dict(self): val = super(Album, self).to_dict() val['type'] = 'album' val['url'] = reverse('mediashop:music_item_detail', args=(self.artist.slug, self.slug)) image_url = self.cover.name if self.cover.name else Service.LOGO_PLACEHOLDER val['image'] = getattr(settings, 'MEDIA_URL') + image_url return val
class Photo(models.Model): UPLOAD_TO = 'photos' image = MultiImageField(upload_to=UPLOAD_TO, max_size=800) def delete(self, *args, **kwargs): try: os.unlink(self.image.path) os.unlink(self.image.small_path) os.unlink(self.image.thumb_path) except: pass super(Photo, self).delete(*args, **kwargs) def __unicode__(self): return self.image.url
class Post(Model): UPLOAD_TO = 'blog/blog_img' category = models.ForeignKey(PostCategory, blank=True, null=True) title = models.CharField(max_length=240, blank=False, unique=True) summary = models.CharField(max_length=240, blank=True) slug = models.SlugField(max_length=240, blank=False, unique=True, editable=False) image = MultiImageField(upload_to=UPLOAD_TO, blank=True, null=True, max_size=800) entry = models.TextField() pub_date = models.DateField(default=datetime.now, editable=False) appear_on_home_page = models.BooleanField(default=False) is_active = models.BooleanField(default=False) member = models.ForeignKey(Member, editable=False) tags = models.CharField(max_length=255, blank=True) likes = models.SmallIntegerField(default=0, editable=False) linked_document = models.FileField(blank=True, upload_to=UPLOAD_TO) rand = models.FloatField(default=random.random, db_index=True, editable=False) consult_count = models.IntegerField(default=10) def __unicode__(self): return "%s" % self.title def get_path(self): folders = '%s' % (self.slug) return '%s' % folders def get_uri(self): base_uri = getattr(settings, 'BASE_URI') return '%s%s' % (base_uri, self.get_path()) def get_image_url(self): if self.image: return self.image.url else: return None def delete(self, *args, **kwargs): for photo in self.image: photo.delete(*args, **kwargs)
class Banner(SmartObject): """ Any of banners owner of the site may use as Slide, Popup, etc to market some products on the site. """ UPLOAD_TO = 'web/banners' image = MultiImageField(upload_to=UPLOAD_TO, blank=True, null=True, max_size=1920) display = models.CharField( max_length=30, choices=DISPLAY_CHOICES, default=SLIDE, help_text="How the image is shown on the site. Can be one of " "<strong>Slide, Popup, FullWidthSection</strong> " "or <strong>FullScreenPopup</strong>") # location = models.CharField(max_length=60, blank=True, # help_text="Bloc of the page where banner should appear. " # "Applies to Default banners only.") cta = models.CharField(verbose_name=_("Call To Action"), max_length=30, blank=True, help_text=_( 'Action you want you visitors to undertake. ' '<em><strong>E.g:</strong> "Buy Now"</em>')) description = models.TextField(blank=True, help_text=_("Description of the category.")) target_url = models.URLField(blank=True) class Meta: unique_together = ( 'slug', 'display', ) ordering = ( '-id', 'slug', ) permissions = (("ik_manage_marketing", _("Manage marketing tools")), )
class Artist(AbstractWatchModel): name = models.CharField(max_length=100, unique=True) slug = models.SlugField(unique=True) photo = MultiImageField(upload_to='artists_photos', required_width=300, required_height=300, allowed_extensions=['jpg', 'jpeg'], blank=True, null=True, help_text=_("JPEG Image, 300 × 300px")) is_active = models.BooleanField(default=True) tags = models.TextField(blank=True, null=True) turnover_history = ListField() earnings_history = ListField() units_sold_history = ListField() total_turnover = models.IntegerField(default=0) total_earnings = models.IntegerField(default=0) total_units_sold = models.IntegerField(default=0) def __unicode__(self): return self.name def _get_image(self): return self.photo image = property(_get_image) def to_dict(self): val = super(Artist, self).to_dict() val['type'] = 'artist' val['url'] = reverse('mediashop:artist_detail', args=(self.slug, )) image_url = self.photo.name if self.photo.name else Service.LOGO_PLACEHOLDER val['image'] = getattr(settings, 'MEDIA_URL') + image_url return val
class Movie(Media): objects = MongoDBManager() MAX_RECENT = 96 TOTAL_RECOMMENDED = 12 # Number of items to recommend in a case where there are enough to recommend MIN_RECOMMENDED = 8 # Number of items to recommend in case where there are not enough after the normal algorithm slug = models.SlugField( unique=True, help_text=_( "Auto-filled. If edited, use only lowercase letters and -. Space is not allowed" " Eg: <strong>tomorrow-never-dies</strong>")) release = models.DateField( blank=True, null=True, help_text=_("Date of release of movie in country of origin.")) synopsis = models.TextField(blank=True) resource = models.CharField( verbose_name=_("Media resource"), max_length=255, blank=True, help_text=_( "Filename (Eg: <strong>Avatar.mp4</strong>) or " "URL (Eg: <strong>http://youtube.com/watch?v=2nYwryHPSs</strong>)") ) resource_mob = models.CharField( verbose_name=_("Mobile media resource"), max_length=255, blank=True, help_text=_( "Filename (Eg: <strong>Avatar.mob.mp4</strong>) or " "URL (Eg: <strong>http://m.youtube.com/watch?v=2nYwryHPSs</strong>). " "Leave blank to copy the same value as above")) poster = MultiImageField(upload_to='movies', blank=True, null=True) price = models.PositiveIntegerField( default=0, editable=is_content_vendor, help_text=_("Cost of sale of this movie to VOD operators.")) view_price = models.FloatField( default=0, help_text=_("Cost to view this movie in streaming.")) download_price = models.FloatField( default=0, help_text=_("Cost to download this movie.")) trailer_resource = models.CharField( max_length=255, blank=True, null=True, help_text=_( "Filename (Eg: <strong>Avatar.mob.mp4</strong>), URL " "Embed code (Eg: <strong><iframe src='...'></iframe></strong>) " "for trailer of this movie.")) provider = models.ForeignKey(Service, editable=False, blank=True, null=True, related_name='+', help_text=_("Provider of this movie.")) fake_orders = models.IntegerField( default=0, help_text=_( "Random value you want customers to think the movie was ordered " "that number of times.")) orders = models.IntegerField( default=0, help_text=_("Number of times movie was actually ordered.")) fake_clicks = models.PositiveIntegerField( default=0, help_text=_("Random value you want customers to think the movie was " "viewed that number of times.")) visible = models.BooleanField( default=True, help_text=_("Check if you want the movie to be visible on the site.")) categories = ListField(EmbeddedModelField('Category'), help_text=_("Categories the movie is part of.")) # Tells whether this Movie is part of an Adult category. # Set automatically upon Movie.save() by checking categories is_adult = models.BooleanField(default=False, verbose_name=_("Adult content")) groups = models.CharField( max_length=100, default='', blank=True, help_text= _("Group the movie belongs to (write lowercase). Will be used for suggestions " "Eg: Write <strong>matrix</strong> for all movies Matrix 1, 2 and 3" )) tags = models.CharField( max_length=150, help_text= _("Key words used to retrieve the movie in search. Typically title of movie written " "lowercase and main actors, all separated by space. Eg: <strong>matrix keanu reaves</strong>" )) # Random field used for random selections in MongoDB rand = models.FloatField(default=random.random, db_index=True, editable=False) owner_fk_list = ListField() count_history = ListField( ) # count can be the number of orders or views of this Media download_history = ListField() earnings_history = ListField() total_count = models.IntegerField(default=0) total_download = models.IntegerField(default=0) total_earnings = models.IntegerField(default=0) current_earnings = models.IntegerField( default=0, help_text= "Earnings generated by the movie since the last reset. Differs " "from total_earnings by the fact that it can be reset at times.") class Meta: if getattr(settings, 'IS_GAME_VENDOR', False): verbose_name = 'Product' def _get_display_orders(self): """ Number of orders(based on fake_orders) of movie in a format suitable for display """ if self.fake_orders < 1000: return self.fake_orders else: num500 = self.fake_orders / 500 return "%d+" % (num500 * 500) display_orders = property(_get_display_orders) def _get_display_clicks(self): """ Number of clicks(based on fake_clicks) of movie in a format suitable for display """ if self.fake_clicks < 1000: return self.fake_clicks else: num500 = self.fake_clicks / 500 return "%d+" % (num500 * 500) display_clicks = property(_get_display_clicks) def _get_categories_to_string(self): categories = [category.title for category in self.categories] return ", ".join(categories) categories_to_string = property(_get_categories_to_string) def _get_type(self): return "movie" type = property(_get_type) def _get_trailer(self): """ Gets the trailer of this movie """ if self.trailer_resource: return Trailer(title='', slug='', size=0, duration=3, resource=self.trailer_resource) trailer = property(_get_trailer) def _get_owner_list(self): owner_list = [] for pk in self.owner_fk_list: try: owner_list.append(Member.objects.get(pk=pk)) except: pass return owner_list owner_list = property(_get_owner_list) def to_dict(self): var = to_dict(self) var['poster'] = { 'url': from_provider(self.poster.url, self.provider) if self.poster.name else 'default_poster.jpg', 'small_url': from_provider(self.poster.small_url, self.provider) if self.poster.name else 'default_poster.jpg', 'thumb_url': from_provider(self.poster.thumb_url, self.provider) if self.poster.name else 'default_poster.jpg' } var['type'] = self.type var['display_orders'] = self.display_orders var['display_clicks'] = self.display_clicks var['load'] = self.load var['display_load'] = self.display_load del (var['filename']) del (var['resource']) del (var['resource_mob']) del (var['synopsis']) del (var['provider_id']) del (var['visible']) del (var['fake_orders']) del (var['fake_clicks']) del (var['categories']) del (var['groups']) del (var['rand']) return var def __unicode__(self): return self.title
class Student(Model): UPLOAD_TO = 'foulassi/students' school = models.ForeignKey(Service, blank=True, null=True, related_name='+', default=get_service_instance) registration_number = models.CharField(_("Registration number"), blank=True, max_length=30, unique=True) first_name = models.CharField(_("First name"), max_length=100, db_index=True) last_name = models.CharField(_("Last name"), max_length=100, db_index=True) gender = models.CharField(_("Gender"), max_length=15, choices=GENDER_CHOICES, db_index=True) dob = models.DateField(_("Date of birth"), db_index=True) pob = models.CharField(_("Place of birth"), max_length=150, blank=True, null=True, db_index=True) birthday = models.IntegerField(blank=True, null=True, db_index=True) photo = MultiImageField(upload_to=UPLOAD_TO, blank=True, null=True, max_size=600, small_size=200, thumb_size=100, editable=False) classroom = models.ForeignKey('school.Classroom', verbose_name=_("Classroom")) is_repeating = models.BooleanField(_("Repeats the class ?"), default=False) year_joined = models.IntegerField( _("Year joined"), default=get_school_year, db_index=True, help_text=_("Year when student joined this school")) score_history = ListField() school_year = models.IntegerField(default=get_school_year, db_index=True) is_confirmed = models.BooleanField( default=False) # Confirmed student cannot be deleted again is_excluded = models.BooleanField( default=False ) # Excluded student does not appear in classroom student list tags = models.TextField(blank=True, null=True, db_index=True) my_kids_expiry = models.DateTimeField(blank=True, null=True) my_kids_expired = models.BooleanField(default=True) has_new = models.BooleanField( default=False, help_text="Whether there's a new information published on this student: " "score, discipline information or invoice.") def __unicode__(self): return self.last_name + ' ' + self.first_name def save(self, **kwargs): if not self.id: # Generate registration number for newly created students self.generate_registration_number() if not self.birthday and self.dob: self.birthday = int(self.dob.strftime('%m%d')) super(Student, self).save(**kwargs) def get_score_list(self, subject, using='default'): from ikwen_foulassi.school.models import Score return Score.objects.using(using).filter( student=self, subject=subject).order_by('session') def set_has_new(self, using='default'): """ Checks whether there's anything new about the Student and sets Student.has_new to True, else sets it to False. """ from ikwen_foulassi.foulassi.models import Invoice from ikwen_foulassi.school.models import Score, DisciplineLogEntry, Assignment now = datetime.now() has_pending_assignment = Assignment.objects.using(using).filter( classroom=self.classroom, deadline__lt=now) has_pending_invoice = Invoice.objects.using(using).filter( student=self, status=Invoice.PENDING).count() > 0 has_new_discipline_info = DisciplineLogEntry.objects.using( using).filter(student=self, was_viewed=False).count() > 0 has_new_score = Score.objects.using(using).filter( student=self, was_viewed=False).count() > 0 self.has_new = has_pending_assignment or has_pending_invoice or has_new_discipline_info or has_new_score def generate_registration_number(self): if self.registration_number: return school_year = str(get_school_year())[-2:] classroom = self.classroom level = classroom.level classroom_info = level.name[0] + level.name[-1] + classroom.name[0] inc = Student.objects.filter(classroom=self).count() + 1 registration_number = '' while True: try: registration_number = "%s%s%s" % (school_year, classroom_info, str(inc).zfill(3)) Student.objects.get( registration_number=registration_number.upper()) inc += 1 except: break self.registration_number = registration_number.upper()
class ProductCategory(AbstractWatchModel): """ Category of :class:`kako.models.Product`. User must select the category from a list so, upon installation of the project some categories must be set. """ UPLOAD_TO = 'kakocase/categories' PLACE_HOLDER = 'no_photo.png' name = models.CharField(_("name"), max_length=100, unique=True, help_text=_("Name of the category.")) slug = models.SlugField(unique=True, help_text=_("Slug of the category.")) description = models.TextField(_("description"), blank=True, help_text=_("Description of the category.")) badge_text = models.CharField( _("badge text"), max_length=25, blank=True, help_text=_("Text in the badge that appears on the category. " "<strong>E.g.:</strong> -20%, -30%, New, etc.")) appear_in_menu = models.BooleanField( _("appear in menu"), default=False, help_text=_("Category will appear in main menu if checked.")) show_on_home = models.BooleanField( _("Show on home ?"), default=True, help_text=_("Check to show a preview of products on home page.")) is_active = models.BooleanField(verbose_name="Active ?", default=True, help_text=_("Make it visible or no.")) order_of_appearance = models.IntegerField( default=1, help_text=_("Order of appearance in a list of categories.")) previews_count = models.IntegerField( _("elements in preview"), default=PRODUCTS_PREVIEWS_PER_ROW, help_text=_("Number of elements in the category preview on home page. " "Must be a multiple of 4.")) items_count = models.IntegerField( default=0, editable=False, help_text="Number of products in this category.") image = MultiImageField(upload_to=UPLOAD_TO, blank=True, null=True, max_size=500) # A list of 366 integer values, each of which representing the number of items of this category # that were traded (sold or delivered) on a day out of the 366 previous (current day being the last) items_traded_history = ListField() turnover_history = ListField() earnings_history = ListField() orders_count_history = ListField() # SUMMARY INFORMATION total_items_traded = models.IntegerField(default=0) total_turnover = models.IntegerField(default=0) total_earnings = models.IntegerField(default=0) total_orders_count = models.IntegerField(default=0) class Meta: verbose_name_plural = 'product categories' def __unicode__(self): return self.name def report_counters_to_umbrella(self): try: umbrella_obj = ProductCategory.objects.using(UMBRELLA).get( slug=self.slug) except: umbrella_obj = ProductCategory.objects.using(UMBRELLA).create( name=self.name, slug=self.slug) set_counters(umbrella_obj) increment_history_field(umbrella_obj, 'items_traded_history') increment_history_field(umbrella_obj, 'turnover_history') increment_history_field(umbrella_obj, 'orders_count_history') umbrella_obj.save(using=UMBRELLA) def delete(self, *args, **kwargs): try: os.unlink(self.image.path) os.unlink(self.image.small_path) os.unlink(self.image.thumb_path) except: pass from ikwen_kakocase.commarketing.models import Banner, SmartCategory for banner in Banner.objects.all(): try: banner.items_fk_list.remove(self.id) banner.items_count = banner.get_category_queryset().count() banner.save() except ValueError: pass for smart_category in SmartCategory.objects.all(): try: smart_category.items_fk_list.remove(self.id) smart_category.items_count = smart_category.get_category_queryset( ).count() smart_category.save() except ValueError: pass super(ProductCategory, self).delete(*args, **kwargs) def get_visible_items(self): product_queryset = self.get_visible_products() service_queryset = self.get_visible_recurring_payment_services() if product_queryset.count() > 0: return list(product_queryset) else: return list(service_queryset) def get_visible_products(self): return self.product_set.filter(visible=True, is_duplicate=False) def get_visible_recurring_payment_services(self): return self.recurringpaymentservice_set.filter(visible=True) def get_suited_previews_count(self): count = len(self.get_visible_items()) / PRODUCTS_PREVIEWS_PER_ROW return count * PRODUCTS_PREVIEWS_PER_ROW
class Banner(Model): UPLOAD_TO = 'Banner' title_header = models.CharField(_("Title's header"), blank=True, null=True) image = MultiImageField(_('Banner image'), allowed_extensions=['jpeg', 'png', 'jpg'], upload_to=UPLOAD_TO, required_width=1920, null=True)
class Module(Model): """ Any application module that might be integrated to a website. Eg. Blog, Donate, Subscriptions """ UPLOAD_TO = 'modules' name = models.CharField(max_length=100, unique=True) slug = models.SlugField(unique=True) logo = models.ImageField(upload_to=UPLOAD_TO, null=True, help_text="Logo of the module (100px x 100px).") monthly_cost = models.FloatField( default=0, help_text="What user pays monthly for this module.") description = models.TextField(blank=True, null=True) title = models.CharField( max_length=30, help_text="Title that appears in the menu bar of the website") image = MultiImageField( upload_to=UPLOAD_TO, max_size=800, null=True, help_text="Image on the module page as the visitor will see it. " "Used to decorate or/and give more explanations.") content = models.TextField( blank=True, null=True, help_text="Text on the module page as the visitor will see it. " "Can be used to give some explanations") is_active = models.BooleanField( default=False, help_text="Check/Uncheck to turn the module Active/Inactive") is_pro = models.BooleanField( default=True, help_text="Designates whether this modules is available " "only to PRO version websites") config_model_name = models.CharField( max_length=100, blank=True, null=True, help_text="Model name of the config for this module.") config_model_admin = models.CharField( max_length=100, blank=True, null=True, help_text="Model Admin of the config for this module.") url_name = models.CharField( max_length=60, help_text="Django url name of the module " "Meaning a name under the form [namespace:]url_name") homepage_section_renderer = models.CharField( max_length=100, help_text="Function that renders the module as " "a homepage section.") class Meta: db_table = 'ikwen_module' def __unicode__(self): return self.name def _get_config_model(self): tokens = self.config_model_name.split('.') model = get_model(tokens[0], tokens[1]) return model config_model = property(_get_config_model) def _get_config(self): try: return self.config_model._default_manager.all()[0] except IndexError: pass config = property(_get_config) def render(self, request=None): renderer = import_by_path(self.homepage_section_renderer) return renderer(self, request)
class Song(AbstractWatchModel): artist = models.ForeignKey(Artist) album = models.ForeignKey(Album, blank=True, null=True) title = models.CharField(max_length=100, db_index=True) slug = models.SlugField(db_index=True) cover = MultiImageField(upload_to='songs_covers', required_width=300, required_height=300, allowed_extensions=['jpg', 'jpeg'], blank=True, null=True, help_text=_("JPEG Image, 300 × 300px")) preview = models.FileField(upload_to='song_previews', blank=True, null=True, editable=False) media = FileField(upload_to='songs', blank=True, null=True, allowed_extensions=['mp3'], callback=generate_song_preview) download_link = models.URLField(blank=True, null=True) cost = models.IntegerField(default=0) is_active = models.BooleanField(default=True) show_on_home = models.BooleanField(default=False) order_of_appearance = models.IntegerField(default=0) tags = models.TextField(blank=True, null=True) turnover_history = ListField() earnings_history = ListField() units_sold_history = ListField() total_turnover = models.IntegerField(default=0) total_earnings = models.IntegerField(default=0) total_units_sold = models.IntegerField(default=0) class Meta: unique_together = ('artist', 'album', 'title') def __unicode__(self): return "%s - %s" % (self.title, self.artist.name) def _get_image(self): if self.cover and self.cover.name: return self.cover if self.album: return self.album.cover image = property(_get_image) def get_obj_details(self): return "XAF %d" % self.cost def to_dict(self): val = super(Song, self).to_dict() val['type'] = 'song' val['url'] = reverse('mediashop:music_item_detail', args=(self.artist.slug, self.slug)) image_url = self.image.name if self.image.name else Service.LOGO_PLACEHOLDER val['image'] = getattr(settings, 'MEDIA_URL') + image_url return val
class CyclicRevival(Model): UPLOAD_TO = 'revival/cyclic_mail_images' service = models.ForeignKey(Service, related_name='+') profile_tag_id = models.CharField(max_length=24, db_index=True) hour_of_sending = models.IntegerField(default=9, db_index=True) days_cycle = models.IntegerField(blank=True, null=True, help_text=_("Run revival every N days")) day_of_week_list = ListField() day_of_month_list = ListField() mail_subject = models.CharField(max_length=150, blank=True, null=True) mail_content = models.TextField(blank=True, null=True) mail_image = MultiImageField(upload_to=UPLOAD_TO, max_size=800, blank=True, null=True) sms_text = models.TextField(blank=True, null=True) next_run_on = models.DateField(default=datetime.now, db_index=True) end_on = models.DateField(db_index=True, blank=True, null=True) items_fk_list = ListField() is_active = models.BooleanField(default=False, db_index=True) is_running = models.BooleanField(default=False, db_index=True) class Meta: unique_together = ('service', 'profile_tag_id', ) def set_next_run_date(self): if self.days_cycle: self.next_run_on = self.next_run_on + timedelta(days=self.days_cycle) elif len(self.day_of_week_list): self.day_of_week_list.sort() today = datetime.now().weekday() + 1 count = len(self.day_of_week_list) try: i = self.day_of_week_list.index(today) if count > 1: i = (i + 1) % count next_day = self.day_of_week_list[i] if next_day > today: ext = next_day - today else: ext = next_day - today + 7 self.next_run_on = self.next_run_on + timedelta(days=ext) except: pass elif len(self.day_of_month_list): self.day_of_month_list.sort() now = datetime.now() today = now.day count = len(self.day_of_month_list) days_count = calendar.monthrange(now.year, now.month)[1] try: i = self.day_of_month_list.index(today) if count > 1: i = (i + 1) % count next_day = self.day_of_month_list[i] if next_day > today: ext = next_day - today else: ext = next_day - today + days_count self.next_run_on = self.next_run_on + timedelta(days=ext) except: pass self.save()
class Series(AbstractWatchModel, MediaInterface): objects = MongoDBManager() SLUG = 'series' title = models.CharField(max_length=100, help_text=_("Title of the series.")) season = models.PositiveSmallIntegerField() slug = models.SlugField( unique=True, help_text= _("Auto filled. But add -seasonX manually. Eg: <strong>arrow-saison3</strong>" )) release = models.DateField( blank=True, null=True, help_text=_("Date of release of movie in country of origin.")) episodes_count = models.PositiveIntegerField( help_text="Number of episodes of this series.") # Number of episodes synopsis = models.TextField() poster = MultiImageField(upload_to='series', blank=True, null=True) provider = models.ForeignKey(Service, editable=False, blank=True, null=True, related_name='+', help_text=_("Provider of this series.")) price = models.IntegerField( default=0, editable=is_content_vendor, help_text=_("Cost of sale of this series to VOD operators.")) view_price = models.IntegerField( default=0, help_text=_("Cost to view all episodes of this series in streaming.")) download_price = models.FloatField( default=0, help_text=_("Cost to download all episodes of this series.")) # Tells whether this Movie is part of an Adult category. # Set automatically upon Series.save() by checking categories is_adult = models.BooleanField(default=False, verbose_name=_("Adult content")) trailer_resource = models.CharField( max_length=255, blank=True, null=True, help_text=_( "Filename (Eg: <strong>Avatar.mob.mp4</strong>), URL " "Embed code (Eg: <strong><iframe src='...'></iframe></strong>) " "for trailer of this movie.")) categories = ListField(EmbeddedModelField('Category'), help_text=_("Categories the series is part of.")) visible = models.BooleanField(default=True) groups = models.CharField( max_length=100, default='', blank=True, help_text= _("Group the series belongs to (write lowercase). Will be used for suggestions " "Eg: Write <strong>scandal</strong> for Scandal season 1, 2, 3 ...")) tags = models.CharField( max_length=150, help_text= _("Key words used to retrieve the series in search. Typically title of movie written " "lowercase and main actors, all separated by space. Eg: <strong>scandal keanu reaves</strong>" )) # Random field used for random selections in MongoDB rand = models.FloatField(default=random.random, db_index=True, editable=False) owner_fk_list = ListField() count_history = ListField( ) # count can be the number of orders or views of this Media download_history = ListField() earnings_history = ListField() total_count = models.IntegerField(default=0) total_download = models.IntegerField(default=0) total_earnings = models.IntegerField(default=0) class Meta: verbose_name_plural = 'Series' unique_together = ( 'title', 'season', ) def _get_full_title(self): """ Gets full title of the Series; that is the title followed by "Season X" """ return "%s - %s %d" % (self.title, _('Season'), self.season) full_title = property(_get_full_title) def _get_display_orders(self): """ Number of orders(based on fake_orders) of the series. Is arbitrarily considered as the number of fake_orders of the first episode of the series. It is returned in a format suitable for display """ query_set = SeriesEpisode.objects.filter(series=self.id) first_episode = query_set[0] if len(query_set) > 0 else None if first_episode: if first_episode.fake_orders < 1000: return first_episode.fake_orders else: num500 = first_episode.fake_orders / 500 return "%d+" % (num500 * 500) else: return 20 # This is an arbitrary value display_orders = property(_get_display_orders) def _get_display_clicks(self): """ Number of clicks(based on fake_clicks) of the series. Is arbitrarily considered as the number of fake_clicks of the first episode of the series. It is returned in a format suitable for display """ query_set = SeriesEpisode.objects.filter(series=self.id) first_episode = query_set[0] if len(query_set) > 0 else None if first_episode: if first_episode.fake_clicks < 1000: return first_episode.fake_clicks else: num500 = first_episode.fake_clicks / 500 return "%d+" % (num500 * 500) else: return 150 # This is an arbitrary value display_clicks = property(_get_display_clicks) def _get_orders(self): """ Calculate the number of orders of the series as the average number of orders of the episodes. """ episodes = SeriesEpisode.objects.filter(series=self.id) if len(episodes) == 0: return 0 total_orders = 0 for episode in episodes: total_orders += episode.orders return total_orders / len(episodes) orders = property(_get_orders) _get_orders.short_description = 'Orders' def _get_clicks(self): """ Calculate the number of clicks of the series as the average number of clicks of the episodes. """ episodes = SeriesEpisode.objects.filter(series=self.id) if len(episodes) == 0: return 0 total_clicks = 0 for episode in episodes: total_clicks += episode.orders return total_clicks / len(episodes) clicks = property(_get_clicks) _get_clicks.short_description = 'Clicks' def _get_size(self): """ Calculate the size of the series by summing up the size of episodes individual files. """ sizes = [ series_episode.size for series_episode in SeriesEpisode.objects.filter(series=self) ] return reduce(lambda x, y: x + y, sizes) if len(sizes) > 0 else 0 size = property(_get_size) def _get_duration(self): """ Calculate the duration of the series by summing up the duration of episodes individual files. """ durations = [ series_episode.duration for series_episode in SeriesEpisode.objects.filter(series=self) ] return reduce(lambda x, y: x + y, durations) if len(durations) > 0 else 0 duration = property(_get_duration) def _get_categories_to_string(self): categories = [category.title for category in self.categories] return ", ".join(categories) categories_to_string = property(_get_categories_to_string) def _get_episodes(self): """ Gets the list of episodes of this series """ return [ series_episode for series_episode in SeriesEpisode.objects.filter(series=self) ] episodes = property(_get_episodes) def _get_seriesepisode_set(self): """ Gets the query_set containing all episodes of this series. This naturally exists in django, but this backward query was intentionally by declaring the field series in class SeriesEpisode as such: series = models.ForeignKey(Series, related_name='+') It was removed because it causes error "RelatedObject has no attribute get_internal_type()" when running lookups like "Series.object.filter(title__contains=some_value)". Since this is internally used by the admin app. We manually restored it by creating the property seriesepisode_set below """ return SeriesEpisode.objects.filter(series=self) seriesepisode_set = property(_get_seriesepisode_set) def _get_trailer(self): """ Gets the trailer of this series """ if self.trailer_resource: return Trailer(title='', slug='', size=0, duration=3, resource=self.trailer_resource) trailer = property(_get_trailer) def _get_type(self): return "series" type = property(_get_type) def _get_owner_list(self): owner_list = [] for pk in self.owner_fk_list: try: owner_list.append(Member.objects.get(pk=pk)) except: pass return owner_list owner_list = property(_get_owner_list) def to_dict(self): var = to_dict(self) var['poster'] = { 'url': from_provider(self.poster.url, self.provider) if self.poster.name else 'default_poster.jpg', 'small_url': from_provider(self.poster.small_url, self.provider) if self.poster.name else 'default_poster.jpg', 'thumb_url': from_provider(self.poster.thumb_url, self.provider) if self.poster.name else 'default_poster.jpg' } var['type'] = self.type var['display_orders'] = self.display_orders var['display_clicks'] = self.display_clicks var['display_load'] = self.display_load var['full_title'] = self.full_title del (var['rand']) del (var['synopsis']) del (var['provider_id']) del (var['visible']) del (var['groups']) del (var['categories']) return var def __unicode__(self): return "%s Season %d" % (self.title, self.season)
class Member(AbstractUser): AVATAR = settings.STATIC_URL + 'ikwen/img/login-avatar.jpg' PROFILE_UPLOAD_TO = 'members/profile_photos' COVER_UPLOAD_TO = 'members/cover_images' MALE = 'Male' FEMALE = 'Female' is_ghost = models.BooleanField( default=False, help_text= "Ghost users are created manually by site owner. They can still register " "normally afterwards. Ghost members are useful because they can be " "enrolled in revivals without actually having an account on the website" ) full_name = models.CharField(max_length=150, db_index=True) tags = models.CharField(max_length=255, blank=True, null=True, db_index=True) phone = models.CharField(max_length=30, db_index=True, blank=True, null=True) gender = models.CharField(max_length=15, blank=True, null=True) dob = models.DateField(blank=True, null=True, db_index=True) birthday = models.IntegerField( blank=True, null=True, db_index=True ) # Integer value of birthday only as MMDD. Eg:1009 for Oct. 09 language = models.CharField(max_length=10, blank=True, null=True, default=get_language) photo = MultiImageField(upload_to=PROFILE_UPLOAD_TO, blank=True, null=True, max_size=600, small_size=200, thumb_size=100) cover_image = models.ImageField(upload_to=COVER_UPLOAD_TO, blank=True, null=True) entry_service = models.ForeignKey( Service, blank=True, null=True, related_name='+', help_text=_( "Service where user registered for the first time on ikwen")) is_iao = models.BooleanField( 'IAO', default=False, editable=False, help_text=_('Designates whether this user is an ' '<strong>IAO</strong> (Ikwen Application Operator).')) is_bao = models.BooleanField( 'Bao', default=False, editable=False, help_text=_( 'Designates whether this user is the Bao in the current service. ' 'Bao is the highest person in a deployed ikwen application. The only that ' 'can change or block Sudo.')) collaborates_on_fk_list = ListField( editable=False, help_text="Services on which member collaborates being the IAO or no.") customer_on_fk_list = ListField( editable=False, help_text="Services on which member was granted mere member access.") group_fk_list = ListField( editable=False, help_text="Groups' ids of the member across different Services.") email_verified = models.BooleanField( _('Email verification status'), default=False, help_text=_('Designates whether this email has been verified.')) phone_verified = models.BooleanField( _('Phone verification status'), default=False, help_text=_('Designates whether this phone number has been ' 'verified by sending a confirmation code by SMS.')) business_notices = models.IntegerField( default=0, help_text="Number of pending business notifications.") personal_notices = models.IntegerField( default=0, help_text="Number of pending personal notifications.") objects = MemberManager() class Meta: db_table = 'ikwen_member' def __unicode__(self): return self.get_username() def save(self, **kwargs): if self.dob: self.birthday = int(self.dob.strftime('%m%d')) super(Member, self).save(**kwargs) def get_short_name(self): "Returns the short name for the user." return self.full_name.split(' ')[0] def _get_display_joined(self): return strftime(self.date_joined, '%y/%m/%d %H:%M') display_date_joined = property(_get_display_joined) def get_from(self, db): add_database_to_settings(db) return type(self).objects.using(db).get(pk=self.id) def get_apps_operated(self): return list(Service.objects.filter(member=self)) def get_status(self): if self.is_active: return 'Active' return 'Blocked' def get_notice_count(self): return self.business_notices + self.personal_notices def get_services(self): return list(set(self.collaborates_on) | set(self.customer_on)) def _get_customer_on(self): from ikwen.accesscontrol.backends import UMBRELLA res = [] for pk in self.customer_on_fk_list: try: res.append(Service.objects.using(UMBRELLA).get(pk=pk)) except: self.customer_on_fk_list.remove(pk) self.save() return res customer_on = property(_get_customer_on) def _get_collaborates_on(self): from ikwen.accesscontrol.backends import UMBRELLA res = [] for pk in self.collaborates_on_fk_list: try: res.append(Service.objects.using(UMBRELLA).get(pk=pk)) except: self.collaborates_on_fk_list.remove(pk) self.save() return res collaborates_on = property(_get_collaborates_on) def _get_profile_tag_list(self): from ikwen.revival.models import MemberProfile, ProfileTag member_profile, change = MemberProfile.objects.get_or_create( member=self) res = [] for pk in member_profile.tag_fk_list: try: res.append( ProfileTag.objects.get(pk=pk, is_active=True, is_auto=False, is_reserved=False)) except: member_profile.tag_fk_list.remove(pk) member_profile.save() return res profile_tag_list = property(_get_profile_tag_list) def _get_preference_list(self): from ikwen.revival.models import MemberProfile, ProfileTag member_profile, change = MemberProfile.objects.get_or_create( member=self) res = [] for pk in member_profile.tag_fk_list: try: res.append( ProfileTag.objects.get(pk=pk, is_active=True, is_auto=True, is_reserved=False)) except: member_profile.tag_fk_list.remove(pk) member_profile.save() return res preference_list = property(_get_preference_list) def propagate_changes(self): for s in self.get_services(): db = s.database add_database_to_settings(db) Member.objects.using(db).filter(pk=self.id)\ .update(email=self.email, phone=self.phone, gender=self.gender, first_name=self.first_name, last_name=self.last_name, full_name=self.first_name + ' ' + self.last_name, photo=self.photo.name, cover_image=self.cover_image.name, phone_verified=self.phone_verified, email_verified=self.email_verified, language=self.language) def propagate_password_change(self, new_password): for s in self.get_services(): db = s.database add_database_to_settings(db) try: m = Member.objects.using(db).get(pk=self.id) m.set_password(new_password) m.save(using=db) except Member.DoesNotExist: pass def add_service(self, service_id): """ Adds the service_id in the collaborates_on_fk_list for this Member """ from ikwen.accesscontrol.backends import UMBRELLA m = Member.objects.using(UMBRELLA).get(pk=self.id) m.customer_on_fk_list.append(service_id) m.save(using=UMBRELLA) def add_group(self, group_id): """ Adds the service_id in the group_fk_list for this Member """ from ikwen.accesscontrol.backends import UMBRELLA m = Member.objects.using(UMBRELLA).get(pk=self.id) m.group_fk_list.append(group_id) m.save(using=UMBRELLA) def to_dict(self): self.collaborate_on_fk_list = [ ] # Empty this as it is useless and may cause error self.customer_on_fk_list = [ ] # Empty this as it is useless and may cause error var = to_dict(self) var['date_joined'] = self.display_date_joined var['status'] = self.get_status() import ikwen.conf.settings var['photo'] = ikwen.conf.settings.MEDIA_URL + self.photo.small_name if self.photo.name else Member.AVATAR member_detail_view = getattr(settings, 'MEMBER_DETAIL_VIEW', 'ikwen:profile') url = reverse(member_detail_view, args=(self.id, )) if member_detail_view == 'ikwen:profile': url = ikwenize(url) var['url'] = url try: var['permissions'] = ','.join( UserPermissionList.objects.get(user=self).permission_fk_list) except UserPermissionList.DoesNotExist: var['permissions'] = '' del (var['password']) del (var['is_superuser']) del (var['is_staff']) del (var['is_active']) return var
class HomepageSection(SmartObject): """ Any full-width section on the homepage """ UPLOAD_TO = 'web/homepage_sections' LEFT = "Left" RIGHT = "Right" CENTER = "Center" TEXT_POSITIONS = ((LEFT, _("Left")), (CENTER, _("Center")), (RIGHT, _("Right"))) content_type = models.CharField( max_length=15, choices=HOME_SECTION_TYPE_CHOICES, help_text=_("Whether it is a flat content or a menu preview.")) image = MultiImageField(upload_to=UPLOAD_TO, blank=True, null=True, max_size=1920) background_image = models.BooleanField( default=False, help_text="Check to make the image cover the " "background of this section") description = models.TextField(blank=True, help_text="Text in the section") text_position = models.CharField(max_length=10, default=RIGHT, choices=TEXT_POSITIONS) cta = models.CharField(verbose_name=_("Call To Action"), max_length=30, blank=True, help_text=_( 'Action you want your visitors to undertake. ' '<em><strong>E.g:</strong> "Join Us Now"</em>')) target_url = models.URLField(blank=True) density = models.CharField(max_length=15, default=COZY, choices=DENSITY_CHOICE) class Meta: ordering = ( 'order_of_appearance', '-id', ) permissions = (("ik_manage_marketing", _("Manage marketing tools")), ) def __unicode__(self): return self.title def _get_row_len(self): config = get_service_instance().config if config.theme and config.theme.display == COMFORTABLE: return 2 elif config.theme and config.theme.display == COZY: return 3 else: return getattr(settings, 'PRODUCTS_PREVIEWS_PER_ROW', 4) def render(self, request=None): if self.content_type == FLAT: c = Context({'section': self}) config = get_service_instance().config tpl = 'webnode/snippets/homepage_section_flat.html' if config.theme and config.theme.template.slug != "": if config.theme.template.slug == 'optimum' or config.theme.template.slug == 'improve': tpl = 'webnode/snippets/homepage_section_flat.html' else: tokens = tpl.split('/') tokens.insert(1, config.theme.template.slug) tpl = '/'.join(tokens) html_template = get_template(tpl) return html_template.render(c) else: # The section points to a Menu try: # The actual menu points to an Item List smart_category = SmartCategory.objects.get( slug=self.description) item_list = [] config = get_service_instance().config for category in smart_category.get_category_queryset(): item_list.extend( list( Item.objects.filter(category=category, visible=True, in_trash=False))) c = Context({ 'item_list': item_list[:self._get_row_len()], 'density': self.density, 'title': smart_category.title, 'config': config }) tpl = 'webnode/snippets/homepage_section_item_list.html' # refix template URI according to the theme used if config.theme and config.theme.template.slug != "": if config.theme.template.slug == 'optimum' or config.theme.template.slug == 'improve': tpl = 'webnode/snippets/homepage_section_item_list.html' else: tokens = tpl.split('/') tokens.insert(1, config.theme.template.slug) tpl = '/'.join(tokens) html_template = get_template(tpl) return html_template.render(c) except SmartCategory.DoesNotExist: # The actual menu points to a Module mod = Module.objects.get(slug=self.description) renderer = import_by_path(mod.homepage_section_renderer) return renderer(self, request)