def get_placeholder_image(self): storage_class = get_storage_class(settings.STATICFILES_STORAGE) storage = storage_class() placeholder = storage.open(settings.PLACEHOLDER_PATH) image = ThumbnailerImageField(placeholder) image.thumbnail_storage = storage self.image = image return image
class Klimatik(BaseModel): id = models.AutoField(primary_key=True, verbose_name=_("Номер")) # Core features title = models.CharField(max_length=255, verbose_name=_("Име")) slug = models.SlugField() price = models.DecimalField(max_digits=8, decimal_places=2, verbose_name=_("Цена")) image = ThumbnailerImageField(upload_to='klimatici', verbose_name=_("Снимка с високо качество")) category = models.ForeignKey(Category, on_delete=models.SET_NULL, null=True, verbose_name=_("Категория")) available = models.BooleanField(verbose_name=_("В наличност")) guarantee_months = models.IntegerField( verbose_name=_("Гаранционен период в месеци")) description = models.TextField(verbose_name=_("Описание")) manufacturer = models.ForeignKey(Manufacturer, null=True, related_name="klimatici", on_delete=models.SET_NULL, verbose_name=_("Производител")) # Detailed specs places_size = models.ForeignKey(PlaceSize, null=True, related_name="klimatici", on_delete=models.SET_NULL, verbose_name=_("Размер на помещенията")) energy_class_warm = models.ForeignKey( EnergyClass, null=True, related_name="klimatici_warm", on_delete=models.SET_NULL, verbose_name=_("Енергиен клас отопление")) energy_class_cold = models.ForeignKey( EnergyClass, null=True, related_name="klimatici_cold", on_delete=models.SET_NULL, verbose_name=_("Енергиен клас охлаждане")) power = models.IntegerField(null=True, verbose_name=_("Мощност"), help_text=_("Мерна единица: BTU")) output_power_warm = models.CharField( max_length=255, null=True, verbose_name=_("Отдавана мощност(отопление)"), help_text=_("Мерна единица: kW")) output_power_cold = models.CharField( max_length=255, null=True, verbose_name=_("Отдавана мощност(охлаждане)"), help_text=_("Мерна единица: kW")) consumed_power_warm = models.CharField( max_length=255, null=True, verbose_name=_("Консумирана мощност(отопление)"), help_text=_("Мерна единица: kW")) consumed_power_cold = models.CharField( max_length=255, null=True, verbose_name=_("Консумирана мощност(охлаждане)"), help_text=_("Мерна единица: kW")) input_voltage = models.CharField(max_length=255, null=True, verbose_name=_("Входно напрежение"), help_text=_("Мерна единица: V")) inside_size = models.CharField( max_length=255, null=True, verbose_name=_("Размери на вътрешното тяло Ш x В x Д"), help_text=_("Мерна единица: MM")) outside_size = models.CharField( max_length=255, null=True, verbose_name=_("Размери на външното тяло Ш x В x Д"), help_text=_("Мерна единица: MM")) inside_weight = models.DecimalField( max_digits=8, decimal_places=2, null=True, verbose_name=_("Тегло на вътрешното тяло"), help_text=_("Мерна единица: Кг.")) outside_weight = models.DecimalField( max_digits=8, decimal_places=2, null=True, verbose_name=_("Тегло на външното тяло"), help_text=_("Мерна единица: Кг.")) cold_agent = models.CharField(max_length=255, null=True, verbose_name=_("Хладилен агент")) origin = models.CharField(max_length=255, null=True, verbose_name=_("Произход"), help_text=_("Пример: Германия")) __original_image = None def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.__original_image = self.image def discount(self): if self.discount_inner: if self.discount_inner.time_end < timezone.now(): self.discount_inner.delete() return Discount.objects.none() else: return self.discount_inner return Discount.objects.none() def has_discount(self): has_discount = False try: has_discount = (self.discount_inner is not None) except Discount.DoesNotExist: pass return has_discount def __str__(self): return _(u'%s (номер %d)') % (self.title, self.id) def save(self, *args, **kwargs): # Generate slug from title self.slug = slugify(unidecode(self.title)) # Prevent same slug while True: try: Klimatik.objects.exclude(id=self.id).get(slug=self.slug) self.slug = u"%s%d" % (self.slug, 1) except Klimatik.DoesNotExist: break if self.has_discount(): if self.price != self.discount_inner.new_price: self.discount_inner.delete_default() # Do actual save super(Klimatik, self).save(*args, **kwargs) # Only watermark if image has changed if self.__original_image != self.image: image = Image.open(self.image.path) image = Imprint(image, "zdrkp", font=ImageFont.truetype( os.path.join(settings.BASE_DIR, "sold_items", "static", "sold_items", "fonts", "ComicSans.ttf"), 18), color=(51, 153, 204, 255), opacity=0.6, margin=(30, 30)) image.save(self.image.path) def rating(self): return self.feedbacks.aggregate( klima_rating=models.Avg('feedback_rating'))['klima_rating'] class Meta: verbose_name = _("климатик") verbose_name_plural = _("климатици")
class Page(models.Model): class Meta: verbose_name = "페이지" verbose_name_plural = "페이지 목록" def __str__(self): return self.title def get_absolute_url(self): return "/%s/" % self.code SPECIAL_CHOICES = ((None, '일반 페이지'), ('root', '루트 페이지'), ('main', '메인 페이지'), ('home', '루트 + 메인')) code = models.SlugField( '페이지 코드', unique=True, help_text='페이지 url로 사용됩니다. 단, "home"의 경우 예외적으로 루트가 됩니다.') page_type = models.CharField('특별한 페이지', null=True, choices=SPECIAL_CHOICES, default=None, max_length=10, help_text=""" 랜딩 페이지: 처음 사이트에 진입하면 표시되는 사이트 입니다. 페이지 코드와 무관하게 루트 주소 "/"를 갖습니다.<br/> 메인 페이지: 페이지 내에서 첫 페이지로 돌아갈 때에 목적지가 되는 페이지 입니다. 로고나 '처음으로' 버튼 등에 링크됩니다.<br/> 랜딩 + 메인: 루트이자 첫 페이지로 대부분의 사이트에서 홈페이지에 해당 됩니다. """) title = models.CharField('페이지 제목', max_length=40) subtitle = models.CharField('페이지 부제목(선택)', max_length=100, blank=True, null=True) featured = ThumbnailerImageField( '타이틀 이미지', upload_to='featured', blank=True, null=True, help_text='이미지 추가 시 페이지 상단에 이미지 타이틀이 표시 됩니다.') content = RichTextUploadingField('PC 페이지 내용', config_name='page') style = models.TextField('CSS', default='', blank=True, null=True, help_text='스타일 시트에 추가할 내용(테그 없이 작성)') mobile_content = RichTextUploadingField('모바일 페이지 내용', config_name='page', blank=True, null=True) mobile_style = models.TextField('CSS', default='', blank=True, null=True, help_text='스타일 시트에 추가할 내용(테그 없이 작성)') script = models.TextField('Script', default='', blank=True, null=True, help_text='페이지에 추가할 스크립트 내용(테그 없이 작성)') template = models.CharField( '커스텀 템플릿', max_length=256, default='', blank=True, null=True, help_text='사이트 기본 템플릿(page.html)을 사용하지 않고 별도 템플릿을 사용하려는 경우 지정') updated = models.DateTimeField('업데이트', auto_now=True) created = models.DateTimeField('생성일', auto_now_add=True) def save(self, force_insert=False, force_update=False, using=None, update_fields=None): if self.page_type == 'main': if Page.objects.filter(page_type='main').exists(): Page.objects.filter(page_type='main').update(page_type=None) if Page.objects.filter(page_type='home').exists(): Page.objects.filter(page_type='home').update(page_type='root') elif self.page_type == 'root': if Page.objects.filter(page_type__in=['home', 'root']).exists(): if Page.objects.filter(page_type='main').exists(): Page.objects.filter(page_type='main').update( page_type=None) Page.objects.filter(page_type__in=['home', 'root']).update( page_type='main') elif self.page_type == 'home': Page.objects.update(page_type=None) super().save(force_insert, force_update, using, update_fields)
class Profile(AbstractBaseClass): """ Модель профиля пользователя. Основная модель, она используется в создаваемых пользователем материалах. """ objects = ProfileManager() ROLE_USER = '******' ROLE_MODEL = 'm' ROLE_COMPANY = 'c' ROLE_DEAD_SOUL = 'd' ROLE_CHOICES = ( (ROLE_USER, 'User'), (ROLE_MODEL, 'Model'), (ROLE_COMPANY, 'Company'), (ROLE_DEAD_SOUL, 'Dead soul'), ) role = models.CharField(max_length=1, choices=ROLE_CHOICES) name = models.CharField("Profile name", max_length=255) city = models.ForeignKey('cities_light.City', null=True) short_description = models.CharField("Short description", max_length=255, default='', null=True, blank=True) description = models.TextField("Description", default='', null=True, blank=True) avatar = ThumbnailerImageField(u"Avatar", upload_to="profile_images", null=True, blank=True) # TODO: replace to state certified = models.BooleanField("Certified by the moderator", default=True) completed = models.BooleanField("Completed information", default=False) address = models.CharField("Address", max_length=255, null=True, blank=True) position = models.PositiveIntegerField(_('position'), null=True, default=None) point = models.PositiveSmallIntegerField(_(u'баллы'), default=0) def is_user(self): """ Проверка, что пользователь является заказчиком """ return self.role == self.ROLE_USER def is_company(self): """ Проверка, что пользователь является компанией """ return self.role == self.ROLE_COMPANY def is_producers(self): """ Проверка, что пользователь имеет права исполнителя """ return self.role in (self.ROLE_MASTER, self.ROLE_COMPANY) def phone(self): """ Получение номера телефона. (Устаревшее) """ phones = self.profilephone_set.all() return phones[0].phone if phones.count() else '' def email(self): """ Получение адреса почты. (Устаревшее) """ emails = self.profileemail_set.all() return emails[0].email if emails.count() else '' def get_avatar(self): """ Получение аватара, если его нет или файл не найден, то дефолтная картинка """ if self.avatar and path.exists(self.avatar.path): ava = self.avatar else: ava = get_thumbnailer(open(settings.DEFAULT_IMAGE), relative_name='default.png') print settings.DEFAULT_IMAGE print ava return ava # Foreign data def get_email(self): """ Получение адреса электронной почты пользователя, с которой он регистрировался """ # if self.role == Profile.ROLE_USER: # return self.user_set.all()[0].email # emails = self.profileemail_set.all() # return emails[0].email if emails.count() else '' return self.user_set.all()[0].email def get_actual_emails(self): """ Получение актуальных адресов электронной почты. Из базы выбираются, только адреса существующих людей. Исключены тестовые. """ emails = list( user.email for user in self.user_set.filter( is_admin=False, is_staff=False, is_active=True ).exclude(Q(email__endswith='loc') | Q(email__endswith='amigostone.ru'))) emails += list(profileemail.email for profileemail in self.profileemail_set.all() .exclude(Q(email__endswith='loc') | Q(email__endswith='amigostone.ru'))) return emails def get_phone(self): """ Получение номера телефона """ phones = self.profilephone_set.all() return phones[0].phone if phones.count() else '' def get_url(self): """ Получение адреса сайта компании или мастера """ urls = self.profileurl_set.all() return urls[0].url if urls.count() else '' # FORMS def get_profile_account_form(self): """ В зависимости от роли пользователя, для редактирования профиля, ему дается определенная форма. Формы в основном отличаются названием полей. """ from accounts.forms import ProfileAccountForm, ProfileMasterForm, ProfileCompanyForm if self.is_user(): return ProfileAccountForm elif self.is_company(): return ProfileCompanyForm else: return ProfileMasterForm def get_profile_account_formset(self): """ Расширенные формы для заполнения профиля. Так же зависят от роли пользователя """ if self.role == 'a': # (Устаревшее) У обычного заказчика нет дополнительных форм return [Profile.get_profile_email_formset(), Profile.get_profile_email_formset()] elif self.role == 'c': # Компания return [Profile.get_profile_email_formset(), Profile.get_profile_email_formset(), Profile.get_profile_url_formset(), Profile.get_profile_contact_person_formset()] else: # Мастер- return [Profile.get_profile_email_formset(), Profile.get_profile_email_formset()] @staticmethod def get_profile_phone_formset(): """ Форма для добавления номера телефона """ from accounts.forms import ProfilePhoneForm return inlineformset_factory(Profile, ProfilePhone, ProfilePhoneForm, extra=1, min_num=1, max_num=1, can_delete=False) @staticmethod def get_profile_email_formset(): """ Форма для добавления электронного почтового адреса """ from accounts.forms import ProfileEmailForm return inlineformset_factory(Profile, ProfileEmail, ProfileEmailForm, extra=1, min_num=1, max_num=1, can_delete=False) @staticmethod def get_profile_url_formset(): """ Форма для добавления электроного адреса компании """ from accounts.forms import ProfileUrlForm return inlineformset_factory(Profile, ProfileUrl, ProfileUrlForm, extra=1, min_num=1, max_num=1, can_delete=False) @staticmethod def get_profile_director_form(): """ Форма для добавления Гендиректора """ from accounts.forms import ProfileDirectorForm return ProfileDirectorForm # return inlineformset_factory(Profile, ProfileDirector, ProfileDirectorForm, extra=1, min_num=1, max_num=1, # can_delete=False) @staticmethod def get_profile_bank_details_form(): """ Форма для добавления банковских реквизитов """ from accounts.forms import ProfileBankDetailsForm return ProfileBankDetailsForm # return inlineformset_factory(Profile, ProfileBankDetails, ProfileBankDetailsForm, extra=1, min_num=1, # max_num=1, can_delete=False) def __unicode__(self): return self.name def get_public_abs_url(self): """ Ссылка на публичный профиль """ return reverse('companies:profile_view', args=[self.slug]) def get_email_settings(self): """ Список доступных подписок на рассылки """ if self.is_user(): f = EmailGroup.PERSON else: f = EmailGroup.COMPANY return EmailSetting.objects.filter(email_groups__title=f) def get_email_subs(self, cached=False): """ Формирование списка подписок на рассылки сгрупированного по темам """ if cached: try: return self._get_email_subs except AttributeError: pass # p = EmailSetting.objects.raw('select es.id, es.group, es.action, es.description, esp.profile_id from email_sender_emailsetting as es ' # 'inner join email_sender_emailgroup_settings as egs on (es.id = egs.emailsetting_id) ' # 'inner join email_sender_emailgroup as eg on (egs.emailgroup_id = eg.id) ' # 'left join email_sender_emailsetting_profiles as esp on (es.id = esp.emailsetting_id and esp.profile_id=%s)' # 'where eg.title="%s" and es.changeable=true' % (self.id, f)) email_settings = self.get_email_settings().filter(changeable=True) accepts = {e.id for e in self.email_settings.all()} setting = namedtuple('ESetting', 'action description accept group') aggregate = sorted( (setting( s.action, s.description, True if s.id in accepts else False, EmailSetting.group_name(s.group)) for s in email_settings ), key=lambda x: x.group) self._get_email_subs = aggregate return aggregate def update_email_subs(self, settings): """ Обновление подписок на рассылки. Получает id-шники, сравнивает с теми которы в базе, после чего добавляет или удаляет. """ new_accepts = set(settings) aggregate = self.get_email_subs(cached=True) all_settings = {s.action for s in aggregate} current_accepts = {s.action for s in aggregate if s.accept} assert new_accepts.issubset(all_settings) to_add = new_accepts - current_accepts to_remove = current_accepts - new_accepts if to_add: to_add = EmailSetting.objects.filter(action__in=to_add) self.email_settings.add(*to_add) if to_remove: to_remove = EmailSetting.objects.filter(action__in=to_remove) self.email_settings.remove(*to_remove) def get_rating(self): from common.models import PointSystem, PointAction rating = 0 for item in self.pointaction_set.all(): rating += item.content_type.pointsystem.point return rating
class Contact(models.Model): frontpage = models.ForeignKey(Landingpage, verbose_name='Лендинг', on_delete=models.DO_NOTHING, related_name='contacts') company_name = models.CharField(max_length=255, null=False, blank=False, default='наименование организации', verbose_name='наименование организации', help_text='наименование организации') phone1 = models.CharField(max_length=20, null=False, blank=False, verbose_name='номер телефона СПб', help_text='не более 20 символов') phone2 = models.CharField(max_length=20, null=True, blank=True, verbose_name='номер телефона Москва', help_text='не более 20 символов') email = models.EmailField(max_length=60, null=False, blank=False, verbose_name='адрес электронной почты', help_text='не более 60 символов') openings = models.CharField(max_length=40, null=True, blank=True, verbose_name='рабочее время', help_text='не более 40 символов') openings_full = models.TextField( max_length=200, null=True, blank=True, verbose_name='рабочее время, полностью', help_text='не более 200 символов, можно использовать HTML тэги') facebook = models.URLField(max_length=120, null=True, blank=True, verbose_name='facebook', help_text='не более 120 символов') vk = models.URLField(max_length=120, null=True, blank=True, verbose_name='вКонтакте', help_text='не более 120 символов') instagram = models.URLField(max_length=120, null=True, blank=True, verbose_name='instagram', help_text='не более 120 символов') twitter = models.URLField(max_length=120, null=True, blank=True, verbose_name='twitter', help_text='не более 120 символов') googleplus = models.URLField(max_length=120, null=True, blank=True, verbose_name='google+', help_text='не более 120 символов') youtube = models.URLField(max_length=120, null=True, blank=True, verbose_name='youtube', help_text='не более 120 символов') odnoklassniki = models.URLField(max_length=120, null=True, blank=True, verbose_name='одноклассники ', help_text='не более 120 символов') address = models.CharField(max_length=200, null=True, blank=True, verbose_name='адрес', help_text='не более 200 символов') map = models.TextField(max_length=500, null=True, blank=True, verbose_name='код для вставки карт на сайт', help_text='не более 500 символов') slogan = models.TextField( max_length=500, null=True, blank=True, verbose_name='промо-текст в подвал', help_text= 'не более 500 символов (рекомендуется 250 и по содержанию близко к SEO-description главной страницы)' ) active = models.BooleanField(verbose_name='активные настройки', null=False, blank=False, default=False) htext_contacts = HTMLField( null=True, blank=True, verbose_name='HTML текст на страницу "контакты"') htext_about = HTMLField(null=True, blank=True, verbose_name='HTML текст на страницу "о нас"') htext_persdata = HTMLField( null=True, blank=True, verbose_name= 'HTML текст на страницу "политика обработки персональных данных"') def get_upload_path(instance, filename): file_name, file_extension = os.path.splitext(filename) return os.path.join("media/logos/", strftime("%Y/%m/%d/"), str(randint(10000000, 99999999)) + file_extension) logo = ThumbnailerImageField( null=True, blank=True, verbose_name='основной логотип', upload_to=get_upload_path, help_text='соотношение сторон должно быть 315*46') main_menu = models.ForeignKey( MenuItem, null=True, blank=True, verbose_name='Основное меню (разделы)', on_delete=models.SET_NULL, related_name='main_menu', ) menu_services = models.ForeignKey( MenuItem, null=True, blank=True, verbose_name='Меню услуги', on_delete=models.SET_NULL, related_name='menu_services', ) menu_countries = models.ForeignKey( MenuItem, null=True, blank=True, verbose_name='Меню страны', on_delete=models.SET_NULL, related_name='menu_countries', ) menu_articles = models.ForeignKey( MenuItem, null=True, blank=True, verbose_name='Меню статьи', on_delete=models.SET_NULL, related_name='menu_articles', ) gallery = models.ForeignKey(GalleryCategory, null=True, blank=True, verbose_name='Фотографии на главной', on_delete=models.SET_NULL) def logo_tag(self): thumb_url = get_thumbnailer(self.logo.name)['admin'].url return mark_safe('<img src="%s" />' % thumb_url) logo_tag.short_description = 'Превью' logo_tag.allow_tags = True def get_logo_url(self): return get_thumbnailer(self.logo.name)['logo'].url def get_phone1_url(self): if self.phone1: return 'tel:' + re.sub(r'[^\+0-9]', '', self.phone1) return '' def get_phone2_url(self): if self.phone2: return 'tel:' + re.sub(r'[^\+0-9]', '', self.phone2) return '' def get_email_url(self): return 'mailto:' + self.email class Meta: verbose_name = 'Настройки сайта' verbose_name_plural = 'Настройки сайта' def __str__(self): return 'Настройки #' + str(self.company_name) @staticmethod def get_active(): contact = Contact.objects.order_by('-active').first() if (not contact): #raise Exception("no any contact information detected") return None return contact @staticmethod def get_frontpage(): contact = Contact.objects.order_by('-active').first() if (not contact): #raise Exception("no any contact information detected") return None return contact.frontpage @staticmethod def get_mainmenu(): contact = Contact.objects.order_by('-active').first() if (not contact): #raise Exception("no any contact information detected") return None if (not contact.main_menu): return None childs = contact.main_menu.get_childs() return childs def get_photos(self): photos = self.gallery.get_photos_all() return photos def get_latest_8_posts(self): return Post.get_latest_posts(8) @staticmethod def get_favorite_pages(): pages = Page.objects.filter(favorite_page=True).all() if (not pages.count): # raise Exception("no any contact information detected") return None return pages
class Landingpage(models.Model): name = models.CharField( max_length=100, verbose_name='название страницы', ) slug = models.SlugField( max_length=200, null=False, blank=False, unique=True, verbose_name='уникальный адрес страницы', ) title = models.CharField( null=True, blank=True, max_length=300, verbose_name='поле title страницы', help_text='не более 300 символов, по умолчанию будет использовано ' '"название страницы" (если не знаете что это такое - спросите у своего SEO-шника)' ) description = models.CharField( null=True, blank=True, max_length=500, verbose_name='поле description страницы', help_text='не более 500 символов, по умолчанию будет использовано ' '"название страницы" (если не знаете что это такое - спросите у своего SEO-шника)' ) helo_text = models.CharField(null=True, blank=True, max_length=50, verbose_name='приветствие', help_text='не более 50 символов') subhelo_text = models.CharField(null=True, blank=True, max_length=100, verbose_name='под приветствие', help_text='не более 100 символов') content_text = models.TextField( null=True, blank=True, max_length=5000, verbose_name='Основной текст', help_text= 'не более 5000 символов. на странице текст выводится в 2 колонки, разбиваясь на 2 более-менее ' 'равные части. Для принудительного разбиения поставьте символ "#" (решетка)' ) def content_text_first(self): m = self.content_text.find('#') if m != -1: return self.content_text[:m] l = len(self.content_text) m = int(l / 2) while self.content_text[m] != ' ': m += 1 return self.content_text[:m] def content_text_second(self): m = self.content_text.find('#') if m != -1: return self.content_text[m + 1:] l = len(self.content_text) m = int(l / 2) while self.content_text[m] != ' ': m += 1 return self.content_text[m + 1:] ########################################################## slides = models.ManyToManyField(Slide, blank=True, verbose_name='слайды', related_name='pages') ########################################################## use_testimonial_section = models.BooleanField( default=True, verbose_name='Секция "Полезные советы"', ) testimonial_header = models.CharField(null=True, blank=True, max_length=100, verbose_name='Заголовок секции') ########################################################## use_fp_section = models.BooleanField( default=True, verbose_name='Секция "Избранные страницы"', ) fp_header = models.CharField(null=True, blank=True, max_length=100, verbose_name='Заголовок секции') fp_action_url = models.CharField(null=True, blank=True, max_length=200, verbose_name='ссылка URL') fp_action_text = models.CharField(null=True, blank=True, max_length=100, verbose_name='Текст кнопки') def get_upload_path(instance, filename): file_name, file_extension = os.path.splitext(filename) return os.path.join("media/lcontent/", strftime("%Y/%m/%d/"), str(randint(10000000, 99999999)) + file_extension) content_image = ThumbnailerImageField(null=True, blank=True, verbose_name='Основное изображение', upload_to=get_upload_path, help_text='') def content_image_tag(self): thumb_url = get_thumbnailer(self.content_image.name)['admin'].url return mark_safe('<img src="%s" />' % thumb_url) content_image_tag.short_description = 'Превью' content_image_tag.allow_tags = True def content_image_url(self): return get_thumbnailer(self.content_image.name)['content_image'].url ########################################################## use_cta_section = models.BooleanField( default=True, verbose_name='Секция "Призыв к действию"', ) cta_header = models.CharField(null=True, blank=True, max_length=100, verbose_name='Заголовок секции') cta_text = models.TextField(null=True, blank=True, max_length=500, verbose_name='Текст секции призыв к действию') cta_action_url = models.CharField(null=True, blank=True, max_length=200, verbose_name='ссылка URL') cta_action_text = models.CharField(null=True, blank=True, max_length=100, verbose_name='Текст кнопки') ########################################################## use_persons_section = models.BooleanField( default=True, verbose_name='Секция "Персонал"', ) persons_header = models.CharField(null=True, blank=True, max_length=100, verbose_name='Заголовок секции') ########################################################## use_banners_section = models.BooleanField( default=True, verbose_name='Секция "Баннеры"', ) banners_header = models.CharField(null=True, blank=True, max_length=100, verbose_name='Заголовок секции') ########################################################## use_userhtml_section = models.BooleanField( default=True, verbose_name='Секция "Пользовательский HTML"', ) userhtml_header = models.CharField(null=True, blank=True, max_length=100, verbose_name='Заголовок секции') userhtml_text = models.TextField(null=True, blank=True, max_length=10000, verbose_name='Пользовательский HTML') ########################################################## use_video_section = models.BooleanField( default=True, verbose_name='Секция "Видео"', ) video_header = models.CharField(null=True, blank=True, max_length=100, verbose_name='Заголовок секции') video_1 = models.CharField(null=True, blank=True, max_length=100, verbose_name='Видео 1') video_2 = models.CharField(null=True, blank=True, max_length=100, verbose_name='Видео 2') ########################################################## use_news_section = models.BooleanField( default=True, verbose_name='Секция "Новости"', ) news_header = models.CharField(null=True, blank=True, max_length=100, verbose_name='Заголовок секции') news_action_url = models.CharField(null=True, blank=True, max_length=200, verbose_name='ссылка URL') news_action_text = models.CharField(null=True, blank=True, max_length=100, verbose_name='Текст кнопки') ########################################################## def __str__(self): return self.name def get_title(self): if (self.title): return self.title return self.name def get_description(self): if (self.description): return self.description return self.name def get_header(self): if (self.header): return self.header return self.name def get_url(self): if (self.slug): return reverse('website.page_by_slug', args=(self.slug, )) return None class Meta: verbose_name = 'Посадочная страница' verbose_name_plural = 'Посадочные страницы' ordering = ('name', ) def get_testimonials_all(self): return Testimonial.objects.filter(frontpage=self).all() @staticmethod def get_sitemap_info(domain): return { 'name': 'landingpage.xml', 'loc': urljoin(domain, 'sitemap/landingpage.xml'), 'lastmod': datetime.now().isoformat() } @staticmethod def get_sitemap(domain, priority): sitemap = [{ 'loc': urljoin(domain, ''), 'lastmod': datetime.now().isoformat(), 'priority': priority }] for url in Landingpage.objects.all(): if Contact.get_frontpage() != url: sitemap.append({ 'loc': urljoin(domain, url.get_url()), 'lastmod': datetime.now().isoformat(), 'priority': priority * 0.8 }) return sitemap
class EcobasaCommunityProfile(models.Model): group = models.OneToOneField(CosinnusGroup, editable=False, related_name='profile') # mandatory name! name = models.CharField(_('name of community'), max_length=255) website = models.URLField(_('link of your communities website'), max_length=100, blank=True, null=True) image = ThumbnailerImageField( verbose_name=_('image'), help_text=_('Header image for the community-profile, minimum resolution 1200x400'), upload_to='community_images', blank=True, null=True) video = models.URLField( verbose_name=_('Video'), help_text=_('Link to a video showing your community'), max_length=255, blank=True, null=True) # contact info contact_telephone = models.CharField(_('telephone'), max_length=255, blank=True, null=True) contact_street = models.CharField(_('street'), max_length=255, blank=True, null=True) contact_location = OSMField(_('Location'), blank=True, null=True) contact_location_lat = LatitudeField( blank=True, null=True) contact_location_lon = LongitudeField( blank=True, null=True) contact_city = models.CharField(_('city'), max_length=255, blank=True, null=True) contact_zipcode = models.CharField(_('zipcode'), max_length=255, blank=True, null=True) contact_country = models.CharField(_('country'), max_length=2, blank=True, choices=COUNTRY_CHOICES, default='ZZ') contact_show = models.BooleanField(_('show address in profile'), default=False, blank=True) # visitors visitors_num = models.PositiveIntegerField( _('maximum number of people you can host'), blank=True, null=True, default=0) visitors_accommodation = models.TextField(_('accommodation for guests'), blank=True, null=True, help_text=_('Where can your visitors sleep? Do you have space for a bus, tents? How is the indoor sleeping situation? Do you have matresses, a couch? Do you have a donations or a pricing model? Required daily working amount or epxeriences?')) # wishlist wishlist_projects = models.TextField( _('Do you have any construction projects? List and describe them together with needed materials, tools, experts, time and knowledge.'), blank=True, null=True) wishlist_materials = TaggableManager(_('What materials do you need?'), through=TaggedWishMaterial, related_name='_wishlist_material', blank=True, help_text=_('A comma-separated list of tags. You can type anything here. You can also chose from other users tags. Connect two words with a "-" to have one tag.')) wishlist_materials_info = models.TextField(_('Do you have any additional info about materials, or details to your request (like condition, when you need them)?'), blank=True, null=True) wishlist_tools = TaggableManager(_('What tools or machines do you need?'), through=TaggedWishTool, related_name='_wishlist_tool', blank=True, help_text=_('A comma-separated list of tags. You can type anything here. You can also chose from other users tags. Connect two words with a "-" to have one tag.')) wishlist_tools_info = models.TextField( _('Do you have any additional info about tools, or details to your request (like condition, when you need them)?'), blank=True, null=True) wishlist_skills = TaggableManager(_('Are you looking for some experts that could help you with a project or problem? Tag their desired skills here:'), through=TaggedWishSkill, related_name='_wishlist_skill', blank=True, help_text=_('A comma-separated list of tags. You can type anything here. You can also chose from other users tags. Connect two words with a "-" to have one tag.')) wishlist_special_needs = models.TextField( _('Special needs (knowledge, information)'), blank=True, null=True) # offers offers_services = TaggableManager(_('Services offered in your community'), through=TaggedOffersService, related_name='_offers_service', blank=True, help_text=_('A comma-separated list of tags. You can type anything here. You can also chose from other users tags. Connect two words with a "-" to have one tag.')) offers_skills = TaggableManager(_('Skills people can learn in your community'), through=TaggedOffersSkill, related_name='_offers_skill', blank=True) offers_creations = TaggableManager(_('Creations/Products'), through=TaggedOffersCreation, related_name='_offers_creation', blank=True, help_text=_('A comma-separated list of tags. You can type anything here. You can also chose from other users tags. Connect two words with a "-" to have one tag.')) offers_materials = TaggableManager(_('Do you have any materials that you produce or that you dont need anymore? (What you throw away, might be useful to somebody else..)'), through=TaggedOffersMaterial, related_name='_offers_material', blank=True, help_text=_('A comma-separated list of tags. You can type anything here. You can also chose from other users tags. Connect two words with a "-" to have one tag.')) offers_tools = TaggableManager(_('Do you have any tools that you produce or that you dont need anymore?'), through=TaggedOffersTool, related_name='_offers_tool', blank=True, help_text=_('A comma-separated list of tags. You can type anything here. You can also chose from other users tags. Connect two words with a "-" to have one tag.')) offers_workshop_spaces = models.TextField(_('Do you have workshop spaces, where people can build/construct/manufacture things?'), blank=True, null=True) offers_learning_seminars = models.TextField(_('Do you offer any seminars that visitors could attend?'), blank=True, null=True) # basic info basic_description = models.TextField( _('Describe your community'), blank=True, null=True) basic_inhabitants = models.CharField( _('how many people live in your community?'), max_length=255, null=True, blank=True) basic_inhabitants_underage = models.PositiveIntegerField( _('how many of them are under 18?'), null=True, blank=True, default=0) basic_brings_together = models.TextField( _('what brings your community together'), blank=True, null=True) MEMBERSHIP_OPEN = 'o' MEMBERSHIP_LOOKING = 'l' MEMBERSHIP_CLOSED = 'c' MEMBERSHIP_CHOICES = ( (MEMBERSHIP_OPEN, _('looking for members')), (MEMBERSHIP_LOOKING, _('looking for volunteers')), (MEMBERSHIP_CLOSED, _('closed for the moment')), ) basic_membership_status = models.CharField(_('member status'), max_length=2, blank=True, choices=MEMBERSHIP_CHOICES, default=MEMBERSHIP_OPEN) class Meta: app_label = 'ecobasa' def __str__(self): return self.name def save(self, *args, **kwargs): # copy profile name to cosinnus group name self.group.name = self.name # ensure the CosinnusGroup is always public! self.group.public = True self.group.save() return super(EcobasaCommunityProfile, self).save(*args, **kwargs)
class ThumbnailedMixin(models.Model): ''' Миксин добавляет поле image необходимо задать: thumbnaled_image_folder - для указания места хранения thumbnaled_prefix - для указания префикса размера в настройках ''' thumbnaled_image_folder = 'images' thumbnaled_prefix = None class Meta: abstract = True def _get_thumbnail_upload_path(self, filename): return get_upload_path(self.thumbnaled_image_folder, filename) image = ThumbnailerImageField( null=True, blank=True, verbose_name=_('Images'), upload_to=_get_thumbnail_upload_path, ) def image_custom_tag_url(self, thumbnail_name): if (self.image): try: thumb_url = get_thumbnailer( self.image.name)[thumbnail_name].url return mark_safe('<img src="%s" />' % thumb_url) except InvalidImageFormatError as e: logger.error('image_tag({}) : {}'.format( self.image.name, str(e))) return None except EasyThumbnailsError as e: logger.error('image_tag({}) : {}'.format( self.image.name, str(e))) return None return None def image_tag(self): return self.image_custom_tag_url('admin') image_tag.short_description = 'Image preview' image_tag.allow_tags = True def image_custom_url(self, thumbnail_name): if (self.image): try: return get_thumbnailer(self.image.name)[thumbnail_name].url except InvalidImageFormatError as e: logger.error('image_thumb_url({}) : {}'.format( self.image.name, str(e))) return None except EasyThumbnailsError as e: logger.error('image_thumb_url({}) : {}'.format( self.image.name, str(e))) return None return None def image_big_url(self): return self.image_custom_url(self.thumbnaled_prefix + '.big') def image_small_url(self): return self.image_custom_url(self.thumbnaled_prefix + '.small') def image_tiny_url(self): return self.image_custom_url(self.thumbnaled_prefix + '.tiny') def image_thumb_url(self): return self.image_custom_url(self.thumbnaled_prefix + '.thumb') # v 1.0.1 - добавлены переводы # v 1.0.2 - добавлена обработка ошибок # v 1.0.2.1 - исправлена ошибка thumbnaled_prefix # v 1.0.3 + image_custom_url
class Book(TimeStampedModel): STATUS_CHOICES = Choices( (0, 'public', _('public')), (1, 'private', _('private')), ) LICENSE_CHOICES = Choices( (0, 'BY', _('BY')), (1, 'BY-SA', _('BY-SA')), (2, 'BY-ND', _('BY-ND')), (3, 'BY-NC', _('BY-NC')), (4, 'BY-NC-SA', _('BY-NC-SA')), (5, 'BY-NC-ND', _('BY-NC-ND')), ) title = models.CharField( verbose_name=_('title'), max_length=250, ) description = models.TextField( verbose_name=_('description'), blank=True, ) category = TreeForeignKey( 'book.Category', verbose_name=_('category'), null=True, blank=True, db_index=True, on_delete=models.SET_NULL, ) thumbnail = ThumbnailerImageField( verbose_name=_('thumbnail'), upload_to=upload_directory_path, blank=True, ) status = models.IntegerField( verbose_name=_('status'), choices=STATUS_CHOICES, default=STATUS_CHOICES.public, db_index=True, ) license = models.IntegerField( verbose_name=_('license'), choices=LICENSE_CHOICES, default=LICENSE_CHOICES.BY, db_index=True, ) owner = models.ForeignKey( settings.AUTH_USER_MODEL, verbose_name=_('owner'), null=True, blank=True, editable=True, on_delete=models.SET_NULL, related_name="%(app_label)s_%(class)s_owned", ) view_count = models.PositiveIntegerField( verbose_name=_('view count'), default=0, ) updated = models.DateTimeField( verbose_name=_('updated date'), null=True, ) objects = BookManager() class Meta: verbose_name = _('book') verbose_name_plural = _('books') def __str__(self): return self.title
class Challenge(models.Model): def __unicode__(self): return self.name def get_absolute_url(self): return reverse('challenge-detail', kwargs={'challenge_id': str(self.id)}) # Auto-add a new wall object when creating new Challenge def save(self, force_insert=False, force_update=False): if self.id is None: #is new super(Challenge, self).save(force_insert, force_update) self.wall = Wall.objects.create(name=self.name, slug='challenge-' + str(self.id)) super(Challenge, self).save(force_insert, force_update) def update_sq(self): # update self.sq = self.questions.aggregate(Avg('sq'))['sq__avg'] self.save() def update_statistics(self): time_to_complete = self.questions.aggregate( Sum('time_to_complete' ))['time_to_complete__sum'] * CHALLENGE_TTC_FAIRNESS_MULTIPLIER # Set minimum package time of 1 minute time_to_complete = min(time_to_complete, CHALLENGE_TTC_MINIMUM) # Round up to nearest minute self.time_to_complete = math.ceil( time_to_complete / 60) * 60 # Round to nearest minute # Home network for e.g. company-specific challenges network = models.ForeignKey(Network, blank=True, null=True) name = models.CharField(max_length=75) description = models.TextField(blank=True) # Users users = models.ManyToManyField(User, through='UserChallenge', related_name='challenges') total_questions = models.IntegerField(default=0) # Number of questions total_resources = models.IntegerField(default=0) # Number of resources time_to_complete = models.IntegerField(editable=False, default=CHALLENGE_TTC_MINIMUM) sq = models.IntegerField(editable=False, null=True) wall = models.OneToOneField(Wall, editable=False, null=True) # Resources (through challengeresource for bookmarks) resources = models.ManyToManyField(Resource, through='ChallengeResource', related_name='challenges') questions = models.ManyToManyField(Question, blank=True, related_name='challenges') image = ThumbnailerImageField(max_length=255, upload_to=challenge_file_path, blank=True, resize_source=dict(size=(50, 50), crop=True)) created = models.DateTimeField(auto_now_add=True) updated = models.DateTimeField(auto_now=True)
class Post(SoftDeletableModel, AbstractPage): STATUS_CHOICES = Choices( (0, 'draft', _('draft')), (1, 'published', _('published')), (2, 'hidden', _('hidden')), ) blog = models.ForeignKey( 'blog.Blog', verbose_name=_('blog'), related_name='posts', on_delete=models.CASCADE, ) slug = models.SlugField( verbose_name=_('slug'), help_text= _('A short label containing only letters, numbers, underscores or hyphens for URL' ), max_length=255, # unique=True, allow_unicode=True, ) excerpt = models.TextField( verbose_name=_('excerpt'), help_text=_('A short description which does not contain HTML tags'), blank=True, ) content = models.TextField(verbose_name=_('content'), ) category = TreeForeignKey( 'blog.Category', verbose_name=_('category'), null=True, blank=True, db_index=True, on_delete=models.SET_NULL, ) tags = TaggableManager( verbose_name=_('tags'), help_text=_('A comma-separated list of tags.'), blank=True, through=TaggedPost, ) thumbnail = ThumbnailerImageField( verbose_name=_('thumbnail'), upload_to=upload_directory_path, blank=True, ) status = models.IntegerField( verbose_name=_('status'), choices=STATUS_CHOICES, default=STATUS_CHOICES.draft, db_index=True, ) allow_highlight = models.BooleanField( verbose_name=_('allow code highlighting'), default=False, ) allow_comments = models.BooleanField( verbose_name=_('allow comments'), default=True, ) published = models.DateTimeField( verbose_name=_('published date'), null=True, ) view_count = models.PositiveIntegerField( verbose_name=_('view count'), default=0, ) ip_address = models.GenericIPAddressField(verbose_name=_('IP address'), ) objects = PostManager() class Meta: verbose_name = _('post') verbose_name_plural = _('posts') def __str__(self): return self.title def __init__(self, *args, **kwargs): super(Post, self).__init__(*args, **kwargs) self.old_status = self.status self.old_published = self.published def save(self, *args, **kwargs): if self.old_status != self.status \ and self.status == Post.STATUS_CHOICES.published \ and self.old_published is None: self.published = now() super(Post, self).save(*args, **kwargs) def get_absolute_url(self): return reverse('blog:post-detail', args=[self.blog.slug, self.pk, self.slug]) def get_previous_post(self): previous_post = Post.objects.published().filter( id__lt=self.id).order_by('-published').first() if previous_post is None: return None return reverse( 'blog:post-detail', args=[self.blog.slug, previous_post.pk, previous_post.slug]) def get_next_post(self): next_post = Post.objects.published().filter( id__gt=self.id).order_by('-published').last() if next_post is None: return None return reverse('blog:post-detail', args=[self.blog.slug, next_post.pk, next_post.slug])
class Jurisdiction(models.Model, RequestHelper): """A jursidiction that you may file FOIA requests in""" levels = (('f', 'Federal'), ('s', 'State'), ('l', 'Local')) name = models.CharField(max_length=50) # slug should be slugify(unicode(self)) slug = models.SlugField(max_length=55) abbrev = models.CharField(max_length=5, blank=True) level = models.CharField(max_length=1, choices=levels) parent = models.ForeignKey( 'self', related_name='children', blank=True, null=True, limit_choices_to=~Q(level='l'), ) hidden = models.BooleanField(default=False) image = ThumbnailerImageField(upload_to='jurisdiction_images', blank=True, null=True) image_attr_line = models.CharField(blank=True, max_length=255, help_text='May use html') public_notes = models.TextField(blank=True, help_text='May use html') aliases = models.TextField(blank=True) # non local observe_sat = models.BooleanField( default=False, help_text='Are holidays observed on Saturdays? ' '(or are they moved to Friday?)') holidays = models.ManyToManyField(Holiday, blank=True) def __unicode__(self): if self.level == 'l': return u'{}, {}'.format(self.name, self.parent.abbrev) else: return self.name def get_absolute_url(self): """The url for this object""" return reverse('jurisdiction-detail', kwargs=self.get_slugs()) def get_slugs(self): """Return a dictionary of slugs for this jurisdiction, for constructing URLs.""" slugs = {} if self.level == 'l': slugs.update({ 'fed_slug': self.parent.parent.slug, 'state_slug': self.parent.slug, 'local_slug': self.slug }) elif self.level == 's': slugs.update({ 'fed_slug': self.parent.slug, 'state_slug': self.slug }) elif self.level == 'f': slugs.update({'fed_slug': self.slug}) return slugs def get_url(self, view): """The url for this object""" view = 'jurisdiction-%s' % view slugs = self.get_slugs() return reverse(view, kwargs=slugs) def save(self, *args, **kwargs): """Normalize fields before saving""" self.slug = slugify(self.slug) self.name = self.name.strip() super(Jurisdiction, self).save(*args, **kwargs) def get_url_flag(self): """So we can call from template""" return self.get_url('flag') @property def legal(self): """Return the legal jurisdiction this jurisdiction falls under This is the parent state for localities, and itself for all others """ if self.level == 'l': return self.parent else: return self def __getattr__(self, attr): """Short cut access to properties stored on the legal jurisdiction""" if attr in {'days', 'waiver', 'has_appeal'}: return getattr(self.legal.law, attr) # if looking for a law relation, but this model does not have one, # do not error, but return None if attr == 'law': return None raise AttributeError('{!r} object has no attribute {!r}'.format( self.__class__.__name__, attr)) def get_day_type(self): """Does this jurisdiction use business or calendar days?""" return 'business' if self.legal.law.use_business_days else 'calendar' def get_law_name(self, abbrev=False): """The law name for the jurisdiction""" if abbrev and self.legal.law.shortname: return self.legal.law.shortname return self.legal.law.name def get_calendar(self): """Get a calendar of business days for the jurisdiction""" if self.legal.law.use_business_days: return HolidayCalendar(self.legal.holidays.all(), self.legal.observe_sat) else: return Calendar() def get_proxy(self): """Get a random proxy user for this jurisdiction""" return User.objects.filter( organizations__plan__slug='proxy', profile__state=self.legal.abbrev, ).order_by('-profile__preferred_proxy').first() def get_requests(self): """State level jurisdictions should return requests from their localities as well.""" if self.level == 's': requests = FOIARequest.objects.filter( Q(agency__jurisdiction=self) | Q(agency__jurisdiction__parent=self)) else: requests = FOIARequest.objects.filter(agency__jurisdiction=self) return requests def get_days(self): """Get days phrase for request language""" if self.days: return '{} {} days, as the statute requires'.format( self.days, self.get_day_type(), ) else: return '10 business days' class Meta: ordering = ['name'] unique_together = ('slug', 'parent')
class Challenge(models.Model): avatar = ThumbnailerImageField( upload_to='img/challenges', verbose_name=_("Avatar")) name = models.CharField(max_length=80, verbose_name=_("Name")) description = models.TextField( null=True, blank=True, verbose_name=_("Description")) location = models.CharField( max_length=80, null=True, blank=True, verbose_name=_("Location")) duration = models.PositiveIntegerField( default=1, null=True, blank=True, verbose_name=_("Duration")) status = models.CharField( max_length=2, choices=challenge_status_choices, default=CHALLENGE_STATUS.UPCOMING, verbose_name=_("Status")) # Even if primary contact person isn't set, despite everything, # value 'contact_person' can be used to identify who has created challenge is_contact_person = models.BooleanField(default=True) contact_person = models.ForeignKey( User, related_name="contact_chl_set", verbose_name=_("Contact Person")) is_alt_person = models.BooleanField(default=False) alt_person_fullname = models.CharField( max_length=80, null=True, blank=True, verbose_name=_("Full name")) alt_person_email = models.EmailField( max_length=80, null=True, blank=True, verbose_name=_("E-mail")) alt_person_phone = models.CharField( max_length=15, blank=True, default='', verbose_name=_("Phone Number")) start_date = models.DateField(verbose_name=_("Start Date")) start_time = models.TimeField(verbose_name=_("Start Time")) organization = models.ForeignKey( Organization, null=True, blank=True, verbose_name=_("Organization")) application = models.CharField( max_length=2, choices=application_choices, default=CHALLENGE_MODE.FREE_FOR_ALL, verbose_name=_("Application")) is_deleted = models.BooleanField(default=False) deleted_reason = models.TextField( null=True, blank=True, verbose_name=_("Reason for deletion")) created_at = models.DateTimeField(auto_now_add=True) class Meta: verbose_name = _('challenge') verbose_name_plural = _('challenges') ordering = ['name',] def __unicode__(self): return unicode(self.name) def get_absolute_url(self): if self.organization: return reverse( 'participe.challenge.views.challenge_detail', kwargs={ "challenge_id": str(self.id), "org_slug": slugify(self.organization.name), "chl_slug": slugify(self.name), }) else: return reverse( 'participe.challenge.views.challenge_detail', kwargs={ "challenge_id": str(self.id), "chl_slug": slugify(self.name), }) def get_full_url(self, request): url = u"http://{0}{1}".format( request.get_host(), self.get_absolute_url()) return url def get_edit_url(self): return reverse( 'participe.challenge.views.challenge_edit', args=[str(self.id)]) def get_acknowledged_qs(self): """Returns participations with Acknowledged status""" return Participation.objects.filter( challenge=self, status=PARTICIPATION_STATE.ACKNOWLEDGED) @property def stat_application_name(self): for code, name in application_choices: if self.application == code: return name return '' @property def stat_status_name(self): for code, name in challenge_status_choices: if self.status == code: return name return '' @property def confirmation_required(self): return self.application == CHALLENGE_MODE.CONFIRMATION_REQUIRED @property def get_waiting_count(self): return Participation.objects.all().filter( challenge=self, status=PARTICIPATION_STATE.WAITING_FOR_CONFIRMATION).count() @property def get_confirmed_count(self): return Participation.objects.all().filter( challenge=self, status=PARTICIPATION_STATE.CONFIRMED).count() @property def has_waiting_for_confirmation(self): if Participation.objects.filter( status=PARTICIPATION_STATE.WAITING_FOR_CONFIRMATION, challenge=self): return True return False @property def has_waiting_for_acknowledgement(self): if Participation.objects.filter( status=PARTICIPATION_STATE.WAITING_FOR_ACKNOWLEDGEMENT, challenge=self): return True return False @property def is_overdue(self): if self.start_date < date.today(): return True return False
class UserProfile(AbstractUser): avatar = ThumbnailerImageField(_('avatar'), upload_to='avatars', null=True, blank=True) met_criteria = ManyToManyField(Criterion, through=MetCriterion, verbose_name=_('met criteria'), related_name='users_met', blank=True, db_index=True) objects = UserManager() unit_related = UserUnitManager() def __unicode__(self): return "%s (%s)" % (self.get_full_name(), self.username) def _criteria_ids_met(self): """Returns a list of ids of the criteria the user has met.""" return self.met_criteria.values_list('id', flat=True) def has_met_qualifications(self, qualifications): """Has the user met the given qualifications? Returns True if all given qualifications has been met """ criteria_met = self._criteria_ids_met() qualification_ids = [] for q in qualifications: qualification_ids.append(q.id) criteria = Criterion.objects \ .filter(qualification__id__in=qualification_ids) \ .values_list('id', flat=True) return set(criteria).issuperset(set(criteria_met)) def qualifications(self): """Which qualifications has the user met? Returns a list of qualification query objects. """ # TODO Should be limited to the qualifications belonging to # TODO the user's units? criteria_met = self._criteria_ids_met() potential_qualifications = Qualification.objects \ .filter(criteria__in=criteria_met) qualifications_met = [] for pq in potential_qualifications: pqc = pq.criteria.values_list('id', flat=True) if set(pqc).issubset(set(criteria_met)): qualifications_met.append(pq.id) q = Qualification.objects.filter(id__in=qualifications_met) return q def qualifications_not_met(self): """Which qualifications (in his/her units) has the user not met? Returns a list of qualification query objects limited by the qualifications in the unit the user belongs to. """ qualifications_met = self.qualifications().values_list('id', flat=True) user_units = self.units.values_list('id', flat=True) qnm = Qualification.objects \ .exclude(id__in=qualifications_met) \ .filter(units__in=user_units) return qnm def qualification_criteria(self, qualification): """ Given a specific qualification, which criteria has the user met and not met? Returns a tuple of met criteria and not met criteria lists, each list item a tuple of (criterion, metcriterion), if the criterion is met, or (criterion, None) if not met. """ criteria_met = [] criteria_not_met = [] for c in qualification.criteria.all(): try: mc = MetCriterion.objects \ .filter(user__id=self.id) \ .filter(criterion__id=c.id) \ .get() criteria_met.append((c, mc)) except MetCriterion.DoesNotExist: criteria_not_met.append((c, None)) return (criteria_met, criteria_not_met) def get_avatar(self): if self.avatar: return self.avatar else: return "avatars/default.jpg" def get_avatar_path(self): if self.avatar: return self.avatar.path else: return os.path.join(settings.STATIC_ROOT, "avatars/default.jpg") def get_avatar_url(self): if self.avatar: return self.avatar.url else: return settings.STATIC_URL + "avatars/default.jpg"
class Article(models.Model): class Meta: verbose_name = 'Article' verbose_name_plural = 'Articles' title = models.CharField('Titre', max_length=80) description = models.CharField('Description', max_length=200) slug = models.SlugField(max_length=80) authors = models.ManyToManyField(User, verbose_name='Auteurs', db_index=True) create_at = models.DateTimeField('Date de création') pubdate = models.DateTimeField('Date de publication', blank=True, null=True, db_index=True) update = models.DateTimeField('Date de mise à jour', blank=True, null=True) subcategory = models.ManyToManyField(SubCategory, verbose_name='Sous-Catégorie', blank=True, null=True, db_index=True) image = ThumbnailerImageField(upload_to=image_path, blank=True, null=True) is_visible = models.BooleanField('Visible en rédaction', default=False, db_index=True) sha_public = models.CharField('Sha1 de la version publique', blank=True, null=True, max_length=80, db_index=True) sha_validation = models.CharField('Sha1 de la version en validation', blank=True, null=True, max_length=80, db_index=True) sha_draft = models.CharField('Sha1 de la version de rédaction', blank=True, null=True, max_length=80, db_index=True) text = models.CharField('chemin relatif du texte', blank=True, null=True, max_length=200) last_reaction = models.ForeignKey('Reaction', blank=True, null=True, related_name='last_reaction', verbose_name='Derniere réaction') is_locked = models.BooleanField('Est verrouillé', default=False) js_support = models.BooleanField('Support du Javascript', default=False) licence = models.ForeignKey(Licence, verbose_name='Licence', blank=True, null=True, db_index=True) objects = ArticleManager() def __unicode__(self): return self.title def delete_entity_and_tree(self): """deletes the entity and its filesystem counterpart""" shutil.rmtree(self.get_path(), 0) Validation.objects.filter(article=self).delete() if self.on_line(): shutil.rmtree(self.get_prod_path()) self.delete() def get_absolute_url(self): return reverse('zds.article.views.view', kwargs={ 'article_pk': self.pk, 'article_slug': slugify(self.title) }) def get_phy_slug(self): return str(self.pk) + "_" + self.slug def get_absolute_url_online(self): return reverse('zds.article.views.view_online', kwargs={ 'article_pk': self.pk, 'article_slug': slugify(self.title) }) def get_edit_url(self): return reverse('zds.article.views.edit') + \ '?article={0}'.format(self.pk) def on_line(self): return (self.sha_public is not None) and (self.sha_public.strip() != '') def in_validation(self): return self.sha_validation is not None def is_draft(self): return self.sha_draft is not None def get_path(self, relative=False): if relative: return None else: return os.path.join(settings.ZDS_APP['article']['repo_path'], self.get_phy_slug()) def load_json(self, path=None, online=False): if path is None: man_path = os.path.join(self.get_path(), 'manifest.json') else: man_path = path if os.path.isfile(man_path): json_data = open(man_path) data = json_reader.load(json_data) json_data.close() if 'licence' in data: data['licence'] = Licence.objects.get(code=data['licence']) return data else: return None def load_json_for_public(self): repo = Repo(self.get_path()) manarticle = get_blob( repo.commit(self.sha_public).tree, 'manifest.json') data = json_reader.loads(manarticle) if 'licence' in data: data['licence'] = Licence.objects.get(code=data['licence']) return data def load_dic(self, article_version): article_version['pk'] = self.pk article_version['slug'] = slugify(article_version['title']) article_version['image'] = self.image article_version['pubdate'] = self.pubdate article_version['is_locked'] = self.is_locked article_version['sha_draft'] = self.sha_draft article_version['sha_validation'] = self.sha_validation article_version['sha_public'] = self.sha_public article_version['last_read_reaction'] = self.last_read_reaction article_version[ 'get_reaction_count'] = Reaction.objects.count_reactions(self) article_version['get_absolute_url'] = reverse( 'zds.article.views.view', args=[self.pk, self.slug]) article_version['get_absolute_url_online'] = reverse( 'zds.article.views.view_online', args=[self.pk, slugify(article_version['title'])]) article_version['update'] = self.update article_version['authors'] = self.authors article_version['tags'] = self.subcategory return article_version def dump_json(self, path=None): if path is None: man_path = os.path.join(self.get_path(), 'manifest.json') else: man_path = path dct = export_article(self) data = json_writer.dumps(dct, indent=4, ensure_ascii=False) json_data = open(man_path, "w") json_data.write(data.encode('utf-8')) json_data.close() def get_text(self): path = os.path.join(self.get_path(), self.text) txt = open(path, "r") txt_contenu = txt.read() txt.close() return txt_contenu.decode('utf-8') def save(self, *args, **kwargs): self.slug = slugify(self.title) if has_changed(self, 'image') and self.image: old = get_old_field_value(self, 'image', 'objects') if old is not None and len(old.name) > 0: root = settings.MEDIA_ROOT name = os.path.join(root, old.name) os.remove(name) super(Article, self).save(*args, **kwargs) def get_reaction_count(self): """Return the number of reactions in the article.""" return Reaction.objects.filter(article__pk=self.pk).count() def get_last_reaction(self): """Gets the last answer in the thread, if any.""" try: last_reaction = Reaction.objects.all()\ .filter(article__pk=self.pk)\ .order_by('pubdate').last() except: last_reaction = None return last_reaction def first_reaction(self): """Return the first post of a topic, written by topic's author.""" return Reaction.objects\ .filter(article=self)\ .order_by('pubdate')\ .first() def last_read_reaction(self): """Return the last post the user has read.""" try: return ArticleRead.objects\ .select_related()\ .filter(article=self, user=get_current_user())\ .latest('reaction__pubdate').reaction except: return self.first_reaction() def first_unread_reaction(self): """Return the first reaction the user has unread.""" try: last_reaction = ArticleRead.objects\ .filter(article=self, user=get_current_user())\ .latest('reaction__pubdate').reaction next_reaction = Reaction.objects.filter( article__pk=self.pk, pubdate__gt=last_reaction.pubdate)\ .select_related("author").first() return next_reaction except: return self.first_reaction() def antispam(self, user=None): """Check if the user is allowed to post in an article according to the SPAM_LIMIT_SECONDS value. If user shouldn't be able to reaction, then antispam is activated and this method returns True. Otherwise time elapsed between user's last reaction and now is enough, and the method will return False. """ if user is None: user = get_current_user() last_user_reactions = Reaction.objects\ .filter(article=self)\ .filter(author=user.pk)\ .order_by('-position') if last_user_reactions \ and last_user_reactions[0] == self.last_reaction: last_user_reaction = last_user_reactions[0] t = datetime.now() - last_user_reaction.pubdate if t.total_seconds( ) < settings.ZDS_APP['forum']['spam_limit_seconds']: return True return False
class Profile(models.Model): """ A userprofile model that provides a short_info, twitter handle, website URL, avatar field and details about number/age of accompanying children This is also used as AUTH_PROFILE_MODULE. """ user = models.OneToOneField(User, related_name='profile') short_info = models.TextField(_('short info'), blank=True) avatar = ThumbnailerImageField(_('avatar'), upload_to='avatars', null=True, blank=True, help_text=avatar_help_text, validators=ValidatorChain().add( validators.avatar_dimension).add( validators.avatar_format, skip_on_error=True)) num_accompanying_children = models.PositiveIntegerField( _('Number of accompanying children'), null=True, blank=True, default=0) age_accompanying_children = models.CharField( _("Age of accompanying children"), blank=True, max_length=20) twitter = models.CharField(_("Twitter"), blank=True, max_length=20, validators=[validators.twitter_username]) website = models.URLField(_("Website"), blank=True) organisation = models.TextField(_('Organisation'), blank=True) full_name = models.CharField(_("Full name"), max_length=255, blank=True) display_name = models.CharField( _("Display name"), max_length=255, help_text=_('What name should be displayed to other people?'), blank=True) addressed_as = models.CharField( _("Address me as"), max_length=255, help_text= _('How should we call you in mails and dialogs throughout the website?' ), blank=True) accept_pysv_conferences = models.BooleanField( _('Allow copying to PySV conferences'), default=False, blank=True) accept_ep_conferences = models.BooleanField( _('Allow copying to EPS conferences'), default=False, blank=True) accept_job_offers = models.BooleanField( _('Allow sponsors to send job offers'), default=False, blank=True) badge_status = models.ManyToManyField('accounts.BadgeStatus', blank=True, verbose_name=_('Badge status'), related_name='profiles') sessions_attending = models.ManyToManyField( 'schedule.Session', blank=True, related_name='attendees', verbose_name=_('Trainings'), limit_choices_to=Q( kind__slug__in=settings.SCHEDULE_ATTENDING_POSSIBLE)) tags = TaggableManager(blank=True) class Meta: permissions = (('send_user_mails', _('Allow sending mails to users through the website')), ('export_guidebook', _('Allow export of guidebook data')), ('see_checkin_info', _('Allow seeing check-in information')), ('perform_purchase', _('Allow performing purchases'))) @cached_property def short_info_rendered(self): return markdown(self.short_info, 'safe')
class Profile(models.Model): GENDER = ( (1, _('Male')), (2, _('Female')), ) AVATAR_SETTINGS = { 'size': (settings.AVATAR_SIZE, settings.AVATAR_SIZE), 'crop': settings.AVATAR_CROP, 'quality': settings.AVATAR_QUALITY, 'subsampling': settings.AVATAR_SUBSAMPLING, 'HIGH_RESOLUTION': True } user = models.OneToOneField(settings.AUTH_USER_MODEL, unique=True, verbose_name=_('name')) gender = models.PositiveSmallIntegerField(_('gender'), choices=GENDER, null=False, blank=False) avatar = ThumbnailerImageField(_('avatar'), null=False, resize_source=AVATAR_SETTINGS) birth_date = models.DateTimeField(_('birth date'), null=False, blank=False) background = models.ImageField(_('background'), upload_to=upload, null=True, blank=True) college = models.CharField(_('college'), max_length=23, null=True, blank=True) city = models.CharField(_('city'), max_length=23, null=True, blank=True) job = models.CharField(_('job'), max_length=23, null=True, blank=True) descriptione = models.CharField(_('descriptione'), max_length=666, null=True, blank=True) objects = models.Manager() def __str__(self): return "%s%s" % (self.user.last_name, self.user.first_name) def get_en_name(self): return self.user.get_full_name() @property def age(self): if not self.birth_date: return False else: today = timezone.now() age = today.year - self.birth_date.year return '%s' % age def get_age(self): return '%s' % self.age
class EcobasaUserProfile(BaseUserProfile): # FIXME: why need tagged* to be part of SKIP_FIELDS? where are they # injected into the model fields? SKIP_FIELDS = ('id', 'user', 'taggedskill', 'taggedinterest', 'taggedproduct', 'taggedwishlist') avatar = ThumbnailerImageField(_('avatar'), upload_to='avatars', null=True, blank=True) GENDER_OTHER = 'o' GENDER_FEMALE = 'f' GENDER_MALE = 'm' GENDER_CHOICES = ( (GENDER_OTHER, '---'), (GENDER_FEMALE, _('Female')), (GENDER_MALE, _('Male')), (GENDER_OTHER, _('Other')), ) gender = models.CharField(_('"gender"'), max_length=2, blank=True, choices=GENDER_CHOICES, default=GENDER_OTHER) birth_date = models.DateField(_('birth date'), default=None, blank=True, null=True) country = models.CharField(_('country'), max_length=2, blank=True, choices=COUNTRY_CHOICES, default='ZZ') city = models.CharField(_('city'), max_length=255, blank=True, null=True) zipcode = models.CharField(_('zipcode'), max_length=255, blank=True, null=True) interests = TaggableManager(_('interests'), through=TaggedInterest, related_name='_interest', blank=True, help_text=_('A comma-separated list of tags. You can type anything here. You can also chose from other users tags. Connect two words with a "-" to have one tag.')) about = models.TextField(_('About you'), blank=True, null=True) ecobasa_what = models.TextField(_('What would you like to use ecobasa mainly for?'), blank=True, null=True) world = models.TextField(_('What do you do to make the world a better place?'), blank=True, null=True) # Offers skills = TaggableManager(_('Skills / Knowledge'), through=TaggedSkill, related_name='_skill', blank=True, help_text=_('What skills do you have? What can you do to help others? What can you teach someone? Connect two words with a "-" to have one tag.')) products = TaggableManager(_('Products'), through=TaggedProduct, related_name='_product', blank=True, help_text=_('Can you manufacture any products, like jewelery, furniture, clothes, soap etc.. ? Connect two words with a "-" to have one tag.')) # Wishlist wishlist = TaggableManager(_('Wishlist'), through=TaggedWishlist, related_name='_wishlist', blank=True, help_text=_('A comma-separated list of tags. You can type anything here. You can also chose from other users tags. Connect two words with a "-" to have one tag.')) # bus fields has_bus = models.BooleanField( _('Do you have a bus or car that you want to take on the tour?'), default=False, blank=True) bus_image = ThumbnailerImageField(_('bus_image'), upload_to='bus_images', null=True, blank=True) bus_has_driving_license = models.BooleanField( _('I have a driving license'), default=False, blank=True) bus_others_can_drive = models.BooleanField( _('Other people can drive it too'), default=False, blank=True) bus_num_passengers = models.PositiveIntegerField( _('How many people can it take'), null=True, blank=True, default=0) bus_consumption = models.PositiveIntegerField( _('Consumption (l/100km)'), null=True, blank=True, default=0) bus_transport = models.BooleanField( _('Can it transport gifts for the communities like materials, or tools?'), default=True, blank=True) objects = BaseUserProfileManager() class Meta: app_label = 'ecobasa'
class Event(BaseModel): class ACTIVITY_TYPES(object): WORKSHOP = 'Workshop' MEETING = 'Meeting' TALK = 'Talk' EVENT = 'Event' EXTERNAL = 'Others' EXPERIMENTA = 'Experimenta' choices = ( (WORKSHOP, _('Workshop')), (MEETING, _('Meeting')), (TALK, _('Talk')), (EVENT, _('Event')), (EXTERNAL, _('Others')), (EXPERIMENTA, 'Experimenta'), ) colors = { WORKSHOP: 'Workshop', MEETING: 'Meeting', TALK: 'Talk', EVENT: 'Event', EXTERNAL: 'others', } class Meta: ordering = ('-highlighted', 'start_date') # foreign keys region = models.ForeignKey( Region, blank=True, null=True, on_delete=models.SET_NULL, verbose_name=_('region'), ) county = models.ForeignKey( County, blank=True, null=True, on_delete=models.SET_NULL, verbose_name=_('county'), ) experts = models.ManyToManyField( 'users.User', verbose_name=_('experts'), related_name='%(app_label)s_%(class)s_experts', blank=True, ) creator = models.ForeignKey( 'users.User', verbose_name=_('creator'), related_name='created_events', null=True, blank=True, on_delete=models.SET_NULL, ) manager = models.ForeignKey( 'users.User', verbose_name=_('manager'), related_name='%(app_label)s_%(class)s_manager', null=True, blank=True, on_delete=models.SET_NULL, ) participants = models.ManyToManyField( 'users.User', verbose_name=_('participants'), related_name='%(app_label)s_%(class)s_participants', blank=True, ) institutions = models.ManyToManyField( 'institutions.Institution', verbose_name=_('institutions'), related_name='%(app_label)s_%(class)s_institutions', blank=True, ) files = models.ManyToManyField( 'documents.File', verbose_name=_('files'), related_name='%(app_label)s_%(class)s_files', blank=True, ) photos = models.ManyToManyField( 'documents.Photo', verbose_name=_('photos'), related_name='%(app_label)s_%(class)s_photos', blank=True, ) # required fields name = models.CharField( _('name'), max_length=100, ) description = models.TextField( _('description'), ) what_does_it_consist_of = models.TextField( u'¿En qué consiste el taller/tipo de actividad?', default='', ) tags = models.CharField( _('tags'), default='', max_length=255, ) presentation = models.FileField( null=True, blank=True, upload_to=file_path, ) address = models.CharField( _('address'), max_length=255, ) place = models.CharField( _('place'), max_length=255, default='', ) # optional fields start_date = models.DateTimeField( _('start date'), null=True, blank=True, ) end_date = models.DateTimeField( _('final date'), null=True, blank=True, ) principal_image = ThumbnailerImageField( _('principal image'), upload_to=file_path, null=True, blank=True, ) activity_type = models.CharField( _('type of activity'), max_length=50, choices=ACTIVITY_TYPES.choices, default=ACTIVITY_TYPES.choices[0][0], ) contact_email = models.EmailField( _('contact email'), null=True, blank=True, ) url = models.URLField( _('url'), null=True, blank=True, ) is_active = models.BooleanField( _('is active'), default=True, ) acreditation = models.BooleanField( _('acreditation'), default=False, ) quota = models.IntegerField( _('quota'), null=True, blank=True, ) google_maps_iframe = models.TextField( _('google maps iframe'), default='', blank=True, ) highlighted = models.BooleanField( _('highlighted'), default=False, ) certification_text = models.TextField( _('certification text'), default='', blank=True, ) objects = EventQueryset.as_manager() @classmethod def get_events_for_calendar(cls, user, start_date, end_date, **kwargs): """ Get events for the calendar by date range """ events = cls.objects.between_dates( start_date, end_date, ).filter(is_active=True) if not user.is_experimenta() and not user.is_staff: events = events.exclude( activity_type=Event.ACTIVITY_TYPES.EXPERIMENTA ) if 'region_id' in kwargs and kwargs['region_id']: events = events.filter(region_id=kwargs['region_id']) if 'hide_events' in kwargs and kwargs['hide_events']: events = events.exclude(activity_type=cls.ACTIVITY_TYPES.EVENT) if 'hide_workshops' in kwargs and kwargs['hide_workshops']: events = events.exclude(activity_type=cls.ACTIVITY_TYPES.WORKSHOP) if 'hide_meetings' in kwargs and kwargs['hide_meetings']: events = events.exclude(activity_type=cls.ACTIVITY_TYPES.MEETING) if 'hide_talks' in kwargs and kwargs['hide_talks']: events = events.exclude(activity_type=cls.ACTIVITY_TYPES.TALK) if 'hide_experimenta' in kwargs and kwargs['hide_experimenta']: events = events.exclude( activity_type=cls.ACTIVITY_TYPES.EXPERIMENTA ) res = [] for event in events: if event.is_activity_active(): event_dict = {} event_dict['title'] = event.name event_dict['start'] = timezone.localtime(event.start_date) event_dict['end'] = timezone.localtime(event.end_date) event_dict['type'] = event.activity_type.lower() event_dict['eventUrl'] = event.get_absolute_url() event_dict['startStr'] = timezone.localtime( event.start_date).time().strftime('%H:%M') event_dict['endStr'] = timezone.localtime( event.end_date).time().strftime('%H:%M') if event.region: event_dict['region'] = event.region.name else: event_dict['region'] = '' if event.county: event_dict['county'] = event.county.name else: event_dict['county'] = '' if not event.is_over(): stage = event.stage_set.active().get_current_stage() if stage: if stage.stage_type == stage.STAGE_TYPE_INSCRIPTION: activity = event.get_base_activity() event_dict['registerUrl'] = reverse( 'user_activity_create', kwargs={'pk': activity.id}, ) res.append(event_dict) return res def __unicode__(self): return self.name # django methods def get_absolute_url(self): return str(reverse( 'event_detail', kwargs={ 'pk': self.pk } )) def save(self, *args, **kwargs): if self.name: self.name = self.name.strip() return super(Event, self).save(*args, **kwargs) # public methods def get_evaluation_average(self): return self.eventevaluation_set.all().aggregate( Avg('satisfaction') )['satisfaction__avg'] def get_invitation_link(self, user, use_https=False): if not user.token: user.set_token() protocol = use_https and 'https' or 'http' path = reverse( 'event_detail_with_login', kwargs={ 'pk': self.pk, 'token': user.token, 'email': user.email, } ) domain = Site.objects.get_current().domain return '{}://{}{}'.format(protocol, domain, path) def get_activities_list_html(self, user): from activities.models import UserActivity # TODO: do this in a single query for Activities user_activities = UserActivity.objects.filter( activity__event=self, user=user, ).select_related('activity') activities = [] for user_activity in user_activities: activity = user_activity.activity activities.append(activity) html = render_to_string( 'emails/includes/activities_list.jade', context={ 'activities': activities, }, ).replace('\n ', '').replace('\n', '') return html def get_base_activity(self): if not self.activity_set.exists(): self.activity_set.create( event=self, name=self.name, region_id=self.region_id, start_date=self.start_date, quota=self.quota, ) return self.activity_set.first() def get_base_comments(self): comments = self.comment_set.base_comments() return comments.prefetch_related('comment_set', 'images') def get_stages(self): return self.stage_set.filter(is_active=True) def get_tags(self): return (tag.strip() for tag in self.tags.split(',')) def is_over(self): if self.end_date: return self.end_date.date() < utils.today() return False def is_activity_active(self): stages = self.stage_set.all() activity = stages.filter(stage_type=Stage.STAGE_TYPE_ACTIVITY) # must be unique if activity.exists(): return activity.first().is_active else: return True def is_experimenta(self): """ Check if this event is an experimenta event """ return self.activity_type == Event.ACTIVITY_TYPES.EXPERIMENTA @classmethod def add_user_to_experimenta_events(cls, user): """ Add user to experimenta events """ experimenta_events = cls.objects.filter( activity_type=cls.ACTIVITY_TYPES.EXPERIMENTA ) for experimenta_event in experimenta_events: activity = experimenta_event.get_base_activity() activity.register_assistant(user) def add_experimenta_users(self): """ Add experimenta users to this event """ experimenta_users = User.experimenta_users() activity = self.get_base_activity() for user in experimenta_users: activity.register_assistant(user) @classmethod def generate(cls, quantity): fake = Faker() events = [] for i in range(quantity): activity_type = Event.ACTIVITY_TYPES.choices[randint(0, 5)] event = { 'name': fake.sentence( nb_words=4, variable_nb_words=True, ext_word_list=None ), 'description': fake.text(), 'activity_type': activity_type[0], 'get_activity_type_display': activity_type[1], 'start_date': fake.date_time_this_month(), } events.append(event) return events @classmethod def get_dict_event_colors(cls): res = {} res[cls.ACTIVITY_TYPES.WORKSHOP] = '#F6A623' res[cls.ACTIVITY_TYPES.MEETING] = '#007AFF' res[cls.ACTIVITY_TYPES.TALK] = '#5856D6' res[cls.ACTIVITY_TYPES.EVENT] = '#FF2D55' res[cls.ACTIVITY_TYPES.EXTERNAL] = '#5AC8FA' res[cls.ACTIVITY_TYPES.EXPERIMENTA] = '#BBFFCC' return res
class UserenaBaseProfile(models.Model): """ Base model needed for extra profile functionality """ PRIVACY_CHOICES = ( ('open', _('Open')), ('registered', _('Registered')), ('closed', _('Closed')), ) MUGSHOT_SETTINGS = {'size': (userena_settings.USERENA_MUGSHOT_SIZE, userena_settings.USERENA_MUGSHOT_SIZE), 'crop': userena_settings.USERENA_MUGSHOT_CROP_TYPE} mugshot = ThumbnailerImageField(_('mugshot'), blank=True, upload_to=upload_to_mugshot, resize_source=MUGSHOT_SETTINGS, help_text=_('A personal image displayed in your profile.')) privacy = models.CharField(_('privacy'), max_length=15, choices=PRIVACY_CHOICES, default=userena_settings.USERENA_DEFAULT_PRIVACY, help_text=_('Designates who can view your profile.')) maxNumberOfInvitationTicket = models.IntegerField(default=3) invitedBy = models.ForeignKey('self',on_delete=models.SET_NULL,null=True,blank=True,related_name='invited_users' ) objects = UserenaBaseProfileManager() class Meta: """ Meta options making the model abstract and defining permissions. The model is ``abstract`` because it only supplies basic functionality to a more custom defined model that extends it. This way there is not another join needed. We also define custom permissions because we don't know how the model that extends this one is going to be called. So we don't know what permissions to check. For ex. if the user defines a profile model that is called ``MyProfile``, than the permissions would be ``add_myprofile`` etc. We want to be able to always check ``add_profile``, ``change_profile`` etc. """ abstract = True permissions = PROFILE_PERMISSIONS def __str__(self): return 'Profile of %(username)s' % {'username': self.user.username} def get_mugshot_url(self): """ Returns the image containing the mugshot for the user. The mugshot can be a uploaded image or a Gravatar. Gravatar functionality will only be used when ``USERENA_MUGSHOT_GRAVATAR`` is set to ``True``. :return: ``None`` when Gravatar is not used and no default image is supplied by ``USERENA_MUGSHOT_DEFAULT``. """ # First check for a mugshot and if any return that. if self.mugshot: return self.mugshot.url # Use Gravatar if the user wants to. if userena_settings.USERENA_MUGSHOT_GRAVATAR: return get_gravatar(self.user.email, userena_settings.USERENA_MUGSHOT_SIZE, userena_settings.USERENA_MUGSHOT_DEFAULT) # Gravatar not used, check for a default image. else: if userena_settings.USERENA_MUGSHOT_DEFAULT not in ['404', 'mm', 'identicon', 'monsterid', 'wavatar']: return userena_settings.USERENA_MUGSHOT_DEFAULT else: return None def get_full_name_or_username(self): """ Returns the full name of the user, or if none is supplied will return the username. Also looks at ``USERENA_WITHOUT_USERNAMES`` settings to define if it should return the username or email address when the full name is not supplied. :return: ``String`` containing the full name of the user. If no name is supplied it will return the username or email address depending on the ``USERENA_WITHOUT_USERNAMES`` setting. """ user = self.user if user.first_name or user.last_name: # We will return this as translated string. Maybe there are some # countries that first display the last name. name = _("%(first_name)s %(last_name)s") % \ {'first_name': user.first_name, 'last_name': user.last_name} else: # Fallback to the username if usernames are used if not userena_settings.USERENA_WITHOUT_USERNAMES: name = "%(username)s" % {'username': user.username} else: name = "%(email)s" % {'email': user.email} return name.strip() def can_view_profile(self, user): """ Can the :class:`User` view this profile? Returns a boolean if a user has the rights to view the profile of this user. Users are divided into four groups: ``Open`` Everyone can view your profile ``Closed`` Nobody can view your profile. ``Registered`` Users that are registered on the website and signed in only. ``Admin`` Special cases like superadmin and the owner of the profile. Through the ``privacy`` field a owner of an profile can define what they want to show to whom. :param user: A Django :class:`User` instance. """ # Simple cases first, we don't want to waste CPU and DB hits. # Everyone. if self.privacy == 'open': return True # Registered users. elif self.privacy == 'registered' \ and isinstance(user, get_user_model()): return True # Checks done by guardian for owner and admins. elif 'view_profile' in get_perms(user, self): return True # Fallback to closed profile. return False def get_remaining_invite_tickets_number(self): if(self.user.has_perm('invite_user')): return self.maxNumberOfInvitationTicket-self.invited_users.all().count() return 0
class Image(models.Model): """Represent an image in database""" class Meta: verbose_name = _('Image') verbose_name_plural = _('Images') gallery = models.ForeignKey('Gallery', verbose_name=_('Galerie'), db_index=True) title = models.CharField(_('Titre'), max_length=80) slug = models.SlugField(max_length=80) physical = ThumbnailerImageField(upload_to=image_path, max_length=200) legend = models.CharField(_('Légende'), max_length=80, null=True, blank=True) pubdate = models.DateTimeField(_('Date de création'), auto_now_add=True, db_index=True) update = models.DateTimeField(_('Date de modification'), null=True, blank=True) def __init__(self, *args, **kwargs): super(Image, self).__init__(*args, **kwargs) def __str__(self): """Human-readable representation of the Image model. :return: Image slug :rtype: unicode """ return self.slug def get_absolute_url(self): """URL of a single Image. :return: Image object URL :rtype: str """ return '{0}/{1}'.format(settings.MEDIA_URL, self.physical).replace('//', '/') def get_thumbnail_url(self): return self.physical['gallery'].url def get_extension(self): """Get the extension of an image (used in tests). :return: the extension of the image :rtype: unicode """ return os.path.splitext(self.physical.name)[1][1:] @staticmethod def has_read_permission(request): return request.user.is_authenticated() def has_object_read_permission(self, request): return UserGallery.objects.filter(gallery=self.gallery, user=request.user).count() == 1 @staticmethod def has_write_permission(request): return request.user.is_authenticated() def has_object_write_permission(self, request): return UserGallery.objects.filter(gallery=self.gallery, user=request.user, mode='W').count() == 1 def save(self, *args, **kwargs): self.update = datetime.datetime.now() super().save(*args, **kwargs)
class Slide(models.Model): SLIDE_SIMPLE = 'SS' SLIDE_WITH_BANNER = 'SB' SLIDE_TYPES_CHOICES = ( (SLIDE_SIMPLE, 'Простой слайд'), (SLIDE_WITH_BANNER, 'Слайд с баннером'), ) type = models.CharField( max_length=2, choices=SLIDE_TYPES_CHOICES, default=SLIDE_SIMPLE, ) def get_upload_path(instance, filename): file_name, file_extension = os.path.splitext(filename) return os.path.join("media/slides/", strftime("%Y/%m/%d/"), str(randint(10000000, 99999999)) + file_extension) background = ThumbnailerImageField(null=True, blank=True, verbose_name='Фон слайда', upload_to=get_upload_path, help_text='') def background_tag(self): if (self.background): thumb_url = get_thumbnailer(self.background.name)['admin'].url return mark_safe('<img src="%s" />' % thumb_url) return None background_tag.short_description = 'Загруженное изображение' background_tag.allow_tags = True def get_background_url(self): if (self.background): return get_thumbnailer( self.background.name)['slide_background'].url return None name = models.CharField( max_length=100, verbose_name='название слайда', ) header = models.CharField( null=True, blank=True, max_length=100, verbose_name='заголовок баннера', ) text1 = models.CharField( null=True, blank=True, max_length=100, verbose_name='текст 1-я строка баннера', ) text2 = models.CharField( null=True, blank=True, max_length=100, verbose_name='текст 2-я строка баннера', ) text3 = models.CharField( null=True, blank=True, max_length=100, verbose_name='текст 3-я строка баннера', ) action_url = models.CharField( null=True, blank=True, max_length=200, verbose_name='URL действия', help_text='URL кнопки, телефона (в зависимости от макета)') action_text = models.CharField( null=True, blank=True, max_length=100, verbose_name='текст действия', help_text='текст кнопки, телефона (в зависимости от макета)') def __str__(self): return self.name def with_banner(self): return self.type == self.SLIDE_WITH_BANNER class Meta: verbose_name = 'Слайд' verbose_name_plural = 'Слайды'
class Agency(models.Model, RequestHelper): """An agency for a particular jurisdiction that has at least one agency type""" name = models.CharField(max_length=255) slug = models.SlugField(max_length=255) jurisdiction = models.ForeignKey(Jurisdiction, related_name='agencies') types = models.ManyToManyField(AgencyType, blank=True) status = models.CharField(choices=( ('pending', 'Pending'), ('approved', 'Approved'), ('rejected', 'Rejected'), ), max_length=8, default='pending') user = models.ForeignKey(User, null=True, blank=True) appeal_agency = models.ForeignKey('self', null=True, blank=True) can_email_appeals = models.BooleanField(default=False) payable_to = models.ForeignKey('self', related_name='receivable', null=True, blank=True) image = ThumbnailerImageField(upload_to='agency_images', blank=True, null=True, resize_source={ 'size': (900, 600), 'crop': 'smart' }) image_attr_line = models.CharField(blank=True, max_length=255, help_text='May use html') public_notes = models.TextField(blank=True, help_text='May use html') stale = models.BooleanField(default=False) manual_stale = models.BooleanField( default=False, help_text='For marking an agency stale by hand.') address = models.TextField(blank=True) location = PointField(blank=True) email = models.EmailField(blank=True) other_emails = fields.EmailsListField(blank=True, max_length=255) contact_salutation = models.CharField(blank=True, max_length=30) contact_first_name = models.CharField(blank=True, max_length=100) contact_last_name = models.CharField(blank=True, max_length=100) contact_title = models.CharField(blank=True, max_length=255) url = models.URLField(blank=True, verbose_name='FOIA Web Page', help_text='Begin with http://') phone = models.CharField(blank=True, max_length=30) fax = models.CharField(blank=True, max_length=30) notes = models.TextField(blank=True) aliases = models.TextField(blank=True) parent = models.ForeignKey('self', null=True, blank=True, related_name='children') website = models.CharField(max_length=255, blank=True) twitter = models.CharField(max_length=255, blank=True) twitter_handles = models.TextField(blank=True) foia_logs = models.URLField(blank=True, verbose_name='FOIA Logs', help_text='Begin with http://') foia_guide = models.URLField(blank=True, verbose_name='FOIA Processing Guide', help_text='Begin with http://') exempt = models.BooleanField(default=False) requires_proxy = models.BooleanField(default=False) objects = AgencyQuerySet.as_manager() def __unicode__(self): return self.name def get_absolute_url(self): """The url for this object""" return reverse('agency-detail', kwargs={ 'jurisdiction': self.jurisdiction.slug, 'jidx': self.jurisdiction.pk, 'slug': self.slug, 'idx': self.pk, }) def save(self, *args, **kwargs): """Save the agency""" self.email = self.email.strip() self.slug = slugify(self.slug) self.name = self.name.strip() super(Agency, self).save(*args, **kwargs) def normalize_fax(self): """Return a fax number suitable for use with phaxio""" fax = ''.join(c for c in self.fax if c.isdigit()) if len(fax) == 10: return '1' + fax if len(fax) == 11 and fax[0] == '1': return fax return None def get_email(self): """Returns an email address to send to""" if self.email: return self.email elif self.normalize_fax(): return self.normalize_fax() else: return '' def get_other_emails(self): """Returns other emails as a list""" return fields.email_separator_re.split(self.other_emails) def link_display(self): """Returns link if approved""" if self.status == 'approved': return mark_safe('<a href="%s">%s</a>' % (self.get_absolute_url(), self.name)) else: return self.name def is_stale(self): """Should this agency be marked as stale? If the latest response to any open request is greater than STALE_DURATION days ago, or if no responses to any open request, if the oldest open request was sent greater than STALE_DURATION days ago. If no open requests, do not mark as stale.""" # check if agency is manually marked as stale if self.manual_stale: return True # find any open requests, if none, not stale foias = self.foiarequest_set.get_open().order_by('date_submitted') if not foias: return False # find the latest response to an open request latest_responses = [] for foia in foias: response = foia.latest_response() if response: latest_responses.append(response) if latest_responses: return min(latest_responses) >= STALE_DURATION # no response to open requests, use oldest open request submit date return (date.today() - foias[0].date_submitted).days >= STALE_DURATION def mark_stale(self, manual=False): """Mark this agency as stale and create a StaleAgencyTask if one doesn't already exist.""" self.stale = True self.manual_stale = manual self.save() try: task, created = StaleAgencyTask.objects.get_or_create( resolved=False, agency=self) if created: logger.info('Created new StaleAgencyTask <%d> for Agency <%d>', task.pk, self.pk) except MultipleObjectsReturned as exception: # If there are multiple StaleAgencyTasks returned, just return the first one. # We only want this method to return a single task. # Also, log the exception as a warning. task = StaleAgencyTask.objects.filter(resolved=False, agency=self).first() logger.warning(exception) return task def unmark_stale(self): """Unmark this agency as stale and resolve all of its StaleAgencyTasks.""" self.stale = False self.manual_stale = False self.save() (StaleAgencyTask.objects.filter(resolved=False, agency=self).update(resolved=True)) def count_thanks(self): """Count how many thanks this agency has received""" return (self.foiarequest_set.filter( communications__thanks=True).distinct().count()) def get_requests(self): """Just returns the foiareqest_set value. Used for compatability with RequestHeper mixin""" return self.foiarequest_set def get_user(self): """Get the agency user for this agency""" try: return self.profile.user except Profile.DoesNotExist: user = User.objects.create_user(unique_username(self.name)) Profile.objects.create( user=user, acct_type='agency', date_update=date.today(), agency=self, ) return user def get_all_known_emails(self): """Get all emails we have associated with this agency""" emails = (FOIACommunication.objects.filter( foia__agency=self, response=True).distinct().values_list('priv_from_who', flat=True).order_by()) return [parseaddr(e)[1].lower() for e in emails if parseaddr(e)[1]] class Meta: # pylint: disable=too-few-public-methods verbose_name_plural = 'agencies'
class Jurisdiction(models.Model, RequestHelper): """A jursidiction that you may file FOIA requests in""" levels = (('f', 'Federal'), ('s', 'State'), ('l', 'Local')) name = models.CharField(max_length=50) # slug should be slugify(unicode(self)) slug = models.SlugField(max_length=55) full_name = models.CharField(max_length=55, blank=True) abbrev = models.CharField(max_length=5, blank=True) level = models.CharField(max_length=1, choices=levels) parent = models.ForeignKey('self', related_name='children', blank=True, null=True) hidden = models.BooleanField(default=False) image = ThumbnailerImageField(upload_to='jurisdiction_images', blank=True, null=True) image_attr_line = models.CharField(blank=True, max_length=255, help_text='May use html') public_notes = models.TextField(blank=True, help_text='May use html') # non local days = models.PositiveSmallIntegerField(blank=True, null=True, help_text='How many days do they' ' have to respond?') observe_sat = models.BooleanField( default=False, help_text='Are holidays observed on Saturdays? ' '(or are they moved to Friday?)') holidays = models.ManyToManyField(Holiday, blank=True) use_business_days = models.BooleanField( default=True, help_text='Response time in business days' ' (or calendar days)?') intro = models.TextField(blank=True, help_text='Intro paragraph for request - ' 'usually includes the pertinant FOI law') law_name = models.CharField(blank=True, max_length=255, help_text='The pertinant FOIA law') waiver = models.TextField( blank=True, help_text='Optional - custom waiver paragraph if ' 'FOI law has special line for waivers') has_appeal = models.BooleanField( default=True, help_text='Does this jurisdiction have an appeals process?') requires_proxy = models.BooleanField(default=False) law_analysis = models.TextField( blank=True, help_text='Our analysis of the state FOIA law, ' 'as a part of FOI95.') def __unicode__(self): if self.level == 'l' and not self.full_name and self.parent: self.full_name = '%s, %s' % (self.name, self.parent.abbrev) self.save() return self.full_name elif self.level == 'l': return self.full_name else: return self.name def __repr__(self): return '<Jurisdiction: %d>' % self.pk def get_absolute_url(self): """The url for this object""" return reverse('jurisdiction-detail', kwargs=self.get_slugs()) def get_slugs(self): """Return a dictionary of slugs for this jurisdiction, for constructing URLs.""" slugs = {} if self.level == 'l': slugs.update({ 'fed_slug': self.parent.parent.slug, 'state_slug': self.parent.slug, 'local_slug': self.slug }) elif self.level == 's': slugs.update({ 'fed_slug': self.parent.slug, 'state_slug': self.slug }) elif self.level == 'f': slugs.update({'fed_slug': self.slug}) return slugs def get_url(self, view): """The url for this object""" view = 'jurisdiction-%s' % view slugs = self.get_slugs() return reverse(view, kwargs=slugs) def save(self, *args, **kwargs): """Normalize fields before saving""" self.slug = slugify(self.slug) self.name = self.name.strip() super(Jurisdiction, self).save(*args, **kwargs) def get_url_flag(self): """So we can call from template""" return self.get_url('flag') def legal(self): """Return the jurisdiction abbreviation for which law this jurisdiction falls under""" if self.level == 'l': return self.parent.abbrev else: return self.abbrev def get_days(self): """How many days does an agency have to reply?""" if self.level == 'l': return self.parent.days else: return self.days def get_day_type(self): """Does this jurisdiction use business or calendar days?""" if self.level == 'l': return 'business' if self.parent.use_business_days else 'calendar' else: return 'business' if self.use_business_days else 'calendar' def get_intro(self): """Intro for requests""" if self.level == 'l': return self.parent.intro else: return self.intro def get_waiver(self): """Waiver paragraph for requests""" if self.level == 'l': return self.parent.waiver else: return self.waiver def get_law_name(self): """The law name for the jurisdiction""" if self.level == 'l': return self.parent.law_name else: return self.law_name def get_calendar(self): """Get a calendar of business days for the jurisdiction""" if self.level == 'l' and not self.parent.use_business_days: return Calendar() elif self.level == 'l' and self.parent.use_business_days: return HolidayCalendar(self.parent.holidays.all(), self.parent.observe_sat) elif not self.use_business_days: return Calendar() else: return HolidayCalendar(self.holidays.all(), self.observe_sat) def get_proxy(self): """Get a random proxy user for this jurisdiction""" from muckrock.accounts.models import Profile proxy = (Profile.objects.filter( acct_type='proxy', state=self.legal()).order_by('-preferred_proxy').first()) if proxy: return proxy.user else: return None def get_state(self): """The state name for the jurisdiction""" # pylint: disable=no-member if self.level == 'l': return self.parent.name else: return self.name def can_appeal(self): """Can you appeal to this jurisdiction?""" if self.level == 'l': return self.parent.has_appeal else: return self.has_appeal def get_requests(self): """State level jurisdictions should return requests from their localities as well.""" if self.level == 's': requests = FOIARequest.objects.filter( Q(jurisdiction=self) | Q(jurisdiction__parent=self)) else: requests = FOIARequest.objects.filter(jurisdiction=self) return requests.exclude(status='started') class Meta: # pylint: disable=too-few-public-methods ordering = ['name'] unique_together = ('slug', 'parent')
class Employee(models.Model): """ Сотрудник """ GENDER_CHOICES = ( ('m', 'мужчина'), ('f', 'женщина'), ) last_name = models.CharField( _('Фамилия'), max_length=255, blank=False, null=False, default='', ) first_name = models.CharField( _('Имя'), max_length=255, blank=False, null=False, default='', ) middle_name = models.CharField( _('Отчество'), max_length=255, blank=True, null=True, ) address = models.CharField( _('Адрес проживания'), max_length=2000, blank=True, null=True, ) birth_date = models.DateField( _('Дата рождения'), blank=False, null=False, default=datetime.date.today, ) gender = models.CharField( _('Пол'), max_length=1, choices=GENDER_CHOICES, blank=True, null=True, ) disability = models.BooleanField( _('Инвалидность'), blank=True, null=True, ) employment_date = models.DateField( _('Дата приема на работу'), blank=False, null=False, default=datetime.date.today, ) pers_number = models.CharField( _('Табельный номер'), max_length=255, blank=True, null=True, ) avatar = ThumbnailerImageField( _('Аватарка'), upload_to ='avatars/', blank=True, null=True, resize_source=dict(size=(128, 128), sharpen=True), ) insurance_number = models.CharField( _('Страховой номер (СНИЛС)'), max_length=255, blank=True, null=True, ) workplace = models.ManyToManyField( Workplace, verbose_name=_('Рабочее место'), related_name='employees', ) fire_date = models.DateField( _('Дата увольнения'), blank=True, null=True, ) company = models.ForeignKey( Company, on_delete=models.PROTECT, blank=False, null=False, verbose_name=_('Компания'), ) class Meta: db_table = 'employee' verbose_name = 'Сотрудник' verbose_name_plural = 'Сотрудники' def __str__(self): return '{} {} {}'.format(self.last_name, self.first_name, self.middle_name if self.middle_name else '') def company_name(self): return self.company.name
class Profile(models.Model): # Gênero MASCULINO = 1 FEMININO = 2 # Papel UNKNOWN = 0 ADMINISTRATOR = 1 ASSISTANT_PROFESSOR = 2 STUDENT = 3 PROFESSOR = 4 SUPERVISOR = 5 RESPOSIBLE = 6 GESTOR_ESCOLAR = 7 SUPER_ENSINO_USER = 8 ROLE_CHOICES = ( (ADMINISTRATOR, 'Administrador'), (ASSISTANT_PROFESSOR, 'Professor Assistente'), (STUDENT, 'Aluno'), (PROFESSOR, 'Professor'), (SUPERVISOR, 'Supervisor'), (RESPOSIBLE, 'Responsável'), (GESTOR_ESCOLAR, 'Gestor Escolar'), (SUPER_ENSINO_USER, 'Super Ensino User'), ) GENERO_OPCOES = ( (MASCULINO, 'Masculino'), (FEMININO, 'Feminino'), ) user = models.OneToOneField(get_user_model(), on_delete=models.CASCADE, blank=True, null=True) role = models.PositiveSmallIntegerField(choices=ROLE_CHOICES, null=True, blank=True) genero = models.PositiveSmallIntegerField(choices=GENERO_OPCOES, default=MASCULINO, null=True, blank=True) imagem = ThumbnailerImageField( upload_to='profile/%Y/%m/%d/', blank=True, null=True, default='static/img/default_avatar_male.jpg') @classmethod def create_profile(cls, baseclass, username, password, nome, email): """Cria um novo perfil de usuário no sistema O perfil do usário é definido pelo valor de role e do tipo da class passado em baseclass. Ex: Para criar um novo perfil de aluno novo_aluno = Aluno.create_profile(Aluno, ...) """ user = get_user_model()() user.username = username user.set_password(password) user.email = email user.save() if type(baseclass) is Aluno: role = cls.STUDENT elif type(baseclass) is Responsavel: role = cls.RESPOSIBLE elif type(baseclass) is Professor: role = cls.PROFESSOR elif type(baseclass) is Gestor: role = cls.GESTOR_ESCOLAR else: role = cls.UNKNOWN instance = baseclass(user=user, nome=nome, role=role) instance.save() return instance def __str__(self): return self.user.username def get_username(self): if self.user is not None: return self.user.username return '' def get_baseclass(self): string_class = [v for k, v in self.ROLE_CHOICES if k == self.role][0] if string_class == 'Gestor Escolar': string_class = 'Gestor' if string_class == 'Responsável': string_class = 'Responsavel' return eval(string_class).objects.get(user=self.user)
class Profile(models.Model): """User profile information for muckrock""" # pylint: disable=too-many-public-methods # pylint: disable=too-many-instance-attributes email_prefs = ( ('never', 'Never'), ('hourly', 'Hourly'), ('daily', 'Daily'), ('weekly', 'Weekly'), ('monthly', 'Monthly'), ) user = models.OneToOneField(User) source = models.CharField( max_length=20, blank=True, choices=( ('foia machine', 'FOIA Machine'), ), ) address1 = models.CharField( max_length=50, blank=True, verbose_name='address' ) address2 = models.CharField( max_length=50, blank=True, verbose_name='address (line 2)' ) city = models.CharField(max_length=60, blank=True) state = USStateField( blank=True, help_text=('Your state will be made public on this site.' 'If you do not want this information to be public,' ' please leave blank.') ) zip_code = models.CharField(max_length=10, blank=True) phone = PhoneNumberField(blank=True) acct_type = models.CharField(max_length=10, choices=ACCT_TYPES) organization = models.ForeignKey( 'organization.Organization', blank=True, null=True, related_name='members', on_delete=models.SET_NULL) # extended information profile = models.TextField(blank=True) location = models.ForeignKey('jurisdiction.Jurisdiction', blank=True, null=True) public_email = models.EmailField(max_length=255, blank=True) pgp_public_key = models.TextField(blank=True) website = models.URLField( max_length=255, blank=True, help_text='Begin with http://' ) twitter = models.CharField(max_length=255, blank=True) linkedin = models.URLField( max_length=255, blank=True, help_text='Begin with http://' ) avatar = ThumbnailerImageField( upload_to='account_images', blank=True, null=True, resize_source={'size': (600, 600), 'crop': 'smart'}, storage=get_image_storage(), ) # provide user access to experimental features experimental = models.BooleanField(default=False) # email confirmation email_confirmed = models.BooleanField(default=False) confirmation_key = models.CharField(max_length=24, blank=True) # email preferences email_pref = models.CharField( max_length=10, choices=email_prefs, default='daily', verbose_name='Digest Frequency', help_text=('Receive updates on site activity as an emailed digest.') ) use_autologin = models.BooleanField( default=True, help_text=('Links you receive in emails from us will contain' ' a one time token to automatically log you in') ) # notification preferences new_question_notifications = models.BooleanField(default=False) org_share = models.BooleanField( default=False, verbose_name='Share', help_text='Let other members of my organization view ' 'my embargoed requests', ) # paid for requests num_requests = models.IntegerField(default=0) # for limiting # of requests / month monthly_requests = models.IntegerField(default=0) date_update = models.DateField() # for Stripe customer_id = models.CharField(max_length=255, blank=True) subscription_id = models.CharField(max_length=255, blank=True) payment_failed = models.BooleanField(default=False) preferred_proxy = models.BooleanField( default=False, help_text='This user will be used over other proxies in the same ' 'state. The account must still be set to type proxy for this to ' 'take affect') # for agency users agency = models.OneToOneField( 'agency.Agency', blank=True, null=True, on_delete=models.SET_NULL, ) def __unicode__(self): return u"%s's Profile" % unicode(self.user).capitalize() def get_absolute_url(self): """The url for this object""" return reverse('acct-profile', kwargs={'username': self.user.username}) def is_advanced(self): """Advanced users can access features basic users cannot.""" advanced_types = ['admin', 'beta', 'pro', 'proxy'] return self.acct_type in advanced_types or self.is_member_of_active_org() def is_member_of(self, organization): """Answers whether the profile is a member of the passed organization""" return self.organization_id == organization.pk def is_member_of_active_org(self): """Answers whether the user is a member of an active organization""" return self.organization is not None and self.organization.active def can_multirequest(self): """Is this user allowed to multirequest?""" return self.is_advanced() def can_view_emails(self): """Is this user allowed to view all emails and private contact information?""" return self.is_advanced() def get_monthly_requests(self): """Get the number of requests left for this month""" not_this_month = self.date_update.month != date.today().month not_this_year = self.date_update.year != date.today().year # update requests if they have not yet been updated this month if not_this_month or not_this_year: self.date_update = date.today() self.monthly_requests = settings.MONTHLY_REQUESTS.get(self.acct_type, 0) self.save() return self.monthly_requests def total_requests(self): """Get sum of paid for requests and monthly requests""" org_reqs = self.organization.get_requests() if self.organization else 0 return self.num_requests + self.get_monthly_requests() + org_reqs def make_request(self): """Decrement the user's request amount by one""" organization = self.organization if organization and organization.get_requests() > 0: organization.num_requests -= 1 organization.save() return True if self.get_monthly_requests() > 0: self.monthly_requests -= 1 elif self.num_requests > 0: self.num_requests -= 1 else: return False self.save() return True def multiple_requests(self, num): """How many requests of each type would be used for this user to make num requests""" request_dict = { 'org_requests': 0, 'monthly_requests': 0, 'reg_requests': 0, 'extra_requests': 0 } org_reqs = self.organization.get_requests() if self.organization else 0 if org_reqs > num: request_dict['org_requests'] = num return request_dict else: request_dict['org_requests'] = org_reqs num -= org_reqs monthly = self.get_monthly_requests() if monthly > num: request_dict['monthly_requests'] = num return request_dict else: request_dict['monthly_requests'] = monthly num -= monthly if self.num_requests > num: request_dict['reg_requests'] = num return request_dict else: request_dict['reg_requests'] = self.num_requests request_dict['extra_requests'] = num - self.num_requests return request_dict def bundled_requests(self): """Returns the number of requests the user gets when they buy a bundle.""" how_many = settings.BUNDLED_REQUESTS[self.acct_type] if self.is_member_of_active_org(): how_many = 5 return how_many def customer(self): """Retrieve the customer from Stripe or create one if it doesn't exist. Then return it.""" # pylint: disable=redefined-variable-type try: if not self.customer_id: raise AttributeError('No Stripe ID') customer = stripe_retry_on_error( stripe.Customer.retrieve, self.customer_id, ) except (AttributeError, stripe.InvalidRequestError): customer = stripe_retry_on_error( stripe.Customer.create, description=self.user.username, email=self.user.email, idempotency_key=True, ) self.customer_id = customer.id self.save() return customer def card(self): """Retrieve the default credit card from Stripe, if one exists.""" card = None customer = self.customer() if customer.default_source: card = stripe_retry_on_error( customer.sources.retrieve, customer.default_source, ) return card def has_subscription(self): """Check Stripe to see if this user has any active subscriptions.""" customer = self.customer() return customer.subscriptions.total_count > 0 def start_pro_subscription(self, token=None): """Subscribe this profile to a professional plan. Return the subscription.""" # create the stripe subscription customer = self.customer() if self.subscription_id: raise AttributeError('Only allowed one active subscription at a time.') if not token and not customer.default_source: raise AttributeError('No payment method provided for this subscription.') subscription = stripe_retry_on_error( customer.subscriptions.create, plan='pro', source=token, idempotency_key=True, ) stripe_retry_on_error(customer.save, idempotency_key=True) # modify the profile object (should this be part of a webhook callback?) self.subscription_id = subscription.id self.acct_type = 'pro' self.date_update = date.today() self.monthly_requests = settings.MONTHLY_REQUESTS.get('pro', 0) self.save() return subscription def cancel_pro_subscription(self): """Unsubscribe this profile from a professional plan. Return the cancelled subscription.""" customer = self.customer() subscription = None # subscription reference either exists as a saved field or inside the Stripe customer # if it isn't, then they probably don't have a subscription. in that case, just make # sure that we demote their account and reset them back to basic. try: if not self.subscription_id and not len(customer.subscriptions.data) > 0: raise AttributeError('There is no subscription to cancel.') if self.subscription_id: subscription_id = self.subscription_id else: subscription_id = customer.subscriptions.data[0].id subscription = stripe_retry_on_error( customer.subscriptions.retrieve, subscription_id, ) subscription = subscription.delete() customer = stripe_retry_on_error(customer.save, idempotency_key=True) except AttributeError as exception: logger.warn(exception) except stripe.error.StripeError as exception: logger.warn(exception) self.subscription_id = '' self.acct_type = 'basic' self.monthly_requests = settings.MONTHLY_REQUESTS.get('basic', 0) self.payment_failed = False self.save() return subscription def pay(self, token, amount, metadata, fee=PAYMENT_FEE): """ Creates a Stripe charge for the user. Should always expect a 1-cent based integer (e.g. $1.00 = 100) Should apply a baseline fee (5%) to all payments. """ # pylint: disable=no-self-use modified_amount = int(amount + (amount * fee)) if not metadata.get('email') or not metadata.get('action'): raise ValueError('The charge metadata is malformed.') stripe_retry_on_error( stripe.Charge.create, amount=modified_amount, currency='usd', source=token, metadata=metadata, idempotency_key=True, ) def generate_confirmation_key(self): """Generate random key used for validating the email address""" key = generate_key(24) self.confirmation_key = key self.save() return key def autologin(self): """Generate an autologin key and value for this user if they set this preference.""" autologin_dict = {} if self.use_autologin: lot = LOT.objects.create(user=self.user, type='slow-login') autologin_dict = {settings.LOT_MIDDLEWARE_PARAM_NAME: lot.uuid} return autologin_dict def wrap_url(self, link, **extra): """Wrap a URL for autologin""" extra.update(self.autologin()) return link + '?' + urlencode(extra) def limit_attachments(self): """Does this user need to have their attachments limited?""" return self.acct_type not in ('admin', 'agency')
class User(AbstractBaseUser, PermissionsMixin, AuditModel): username = models.CharField( 'Usuário', max_length=30, default=uuid.uuid4, unique=True, validators=[ validators.RegexValidator( re.compile('^[\w.@+-]+$'), 'Informe um nome de usuário válido. ' 'Este valor deve conter apenas letras, números ' 'e os caracteres: @/./+/-/_ .', 'invalid') ], help_text= 'Um nome curto que será usado para identificá-lo de forma única na plataforma' ) name = models.CharField('Nome', max_length=100, blank=False, null=False) email = models.EmailField('E-mail', unique=True, blank=False, null=False) is_staff = models.BooleanField('Equipe', default=False) is_active = models.BooleanField('Ativo', default=True) is_superuser = models.BooleanField('Super-Usuário', default=False) date_joined = models.DateTimeField('Data de Entrada', auto_now_add=True) cpf = models.CharField('CPF', max_length=14, blank=True, null=True) MALE = 'M' FEMALE = 'F' SEX_CHOICES = ( (MALE, 'Masculino'), (FEMALE, 'Feminino'), ) sex = models.CharField('Sexo', max_length=1, choices=SEX_CHOICES, default=FEMALE) phone = models.CharField('Celular', max_length=16, blank=True, null=True) is_whatsapp = models.BooleanField('O celular é WhatsApp?', default=False) avatar = ThumbnailerImageField(upload_to="avatar", blank=True, resize_source=dict(size=(215, 215), crop=True)) objects = UserManager() EMAIL_FIELD = 'email' USERNAME_FIELD = 'username' REQUIRED_FIELDS = ['email'] class Meta: verbose_name = 'Usuário' verbose_name_plural = 'Usuários' ordering = ['name'] def __str__(self): return self.name or self.username def get_full_name(self): return str(self) def get_short_name(self): return str(self).split(" ")[0]
class LandingPage(models.Model): BODY_TYPES = { "city_council": _("Міська рада"), "regional_council": _("Обласна рада"), "other": _("Інше"), } slug = models.SlugField("Ідентифікатор сторінки", primary_key=True, max_length=100) title = models.CharField("Заголовок сторінки", max_length=200) description = RichTextField("Опис сторінки", blank=True) title_en = models.CharField("Заголовок сторінки [en]", max_length=200, blank=True) description_en = RichTextField("Опис сторінки [en]", blank=True) image = ThumbnailerImageField(blank=True, upload_to="landings") region = models.ForeignKey(Region, blank=True, null=True, on_delete=models.SET_NULL) body_type = models.CharField( "Тип держоргану", blank=True, null=True, choices=BODY_TYPES.items(), max_length=30, ) keywords = models.TextField( "Ключові слова для пошуку в деклараціях (по одному запиту на рядок)", blank=True) def pull_declarations(self): for p in self.persons.select_related("body").prefetch_related( "declarations"): p.pull_declarations() def get_summary(self): persons = {} min_years = [] max_years = [] for p in self.persons.select_related("body").prefetch_related( "declarations"): summary = p.get_summary() if "min_year" in summary: min_years.append(summary["min_year"]) if "max_year" in summary: max_years.append(summary["max_year"]) persons[p.pk] = summary return { "max_year": max(max_years), "min_year": min(min_years), "persons": persons, } def __str__(self): return "%s (%s)" % (self.title, self.slug) def get_absolute_url(self): return reverse("landing_page_details", kwargs={"pk": self.pk}) class Meta: verbose_name = "Лендінг-сторінка" verbose_name_plural = "Лендінг-сторінки"
class LBForumUserProfile(models.Model): user = models.OneToOneField(settings.AUTH_USER_MODEL, related_name='lbforum_profile', verbose_name=_('User')) nickname = models.CharField(_("Nickname"), max_length=255, blank=False, default='') avatar = ThumbnailerImageField(_("Avatar"), upload_to='imgs/avatars', blank=True, null=True) my_like_classes = models.CharField(max_length=2000, default="[]") my_taken_classes = models.CharField(max_length=2000, default="[]") friends = models.CharField(max_length=2000, default='[]') chatList = models.CharField(max_length=2000, default='{}') bio = models.TextField(blank=True) def __str__(self): return self.nickname or self.user.username def change_class(self, class_id, new_att): like_classes = self.get_like_classes() taken_classes = self.get_taken_classes() old = "not interested" if class_id in like_classes: like_classes.remove(class_id) old = "like" if class_id in taken_classes: taken_classes.remove(class_id) old = "taken" if new_att == "taken": taken_classes.append(class_id) if new_att == "like": like_classes.append(class_id) self.set_class(like_classes, 1) self.set_class(taken_classes, 2) return old def add_friend(self, user_id): friends = self.get_friend() if user_id not in friends: friends.append(user_id) self.set_friend(friends) def get_like_classes(self): return json.loads(self.my_like_classes) def get_taken_classes(self): return json.loads(self.my_taken_classes) def get_class(self): classes = self.get_like_classes() + self.get_taken_classes() classes = list(set(classes)) return classes def set_class(self, x, op): if op == 1: self.my_like_classes = json.dumps(x) else: self.my_taken_classes = json.dumps(x) self.save() def get_chat_list(self): return json.loads(self.chatList) def add_chat(self, other, topic_id): chat_list = self.get_chat_list() if other not in chat_list.keys(): chat_list[other] = topic_id self.chatList = json.dumps(chat_list) self.save() def get_friend(self): return json.loads(self.friends) def set_friend(self, x): self.friends = json.dumps(x) self.save() def get_total_topics(self): return self.user.topic_set.count() def get_total_posts(self): return self.user.post_set.count() def get_absolute_url(self): return self.user.get_absolute_url() def get_avatar_url(self, size=48): if not self.avatar: return '%s%s' % ( settings.STATIC_URL, 'lbforum/imgs/avatar.png', ) options = {'size': (size, size), 'crop': True} return get_thumbnailer(self.avatar).get_thumbnail(options).url def get_large_avatar_url(self): return self.get_avatar_url(80)
class CustomUser(AbstractUser): middle_name = models.CharField(max_length=hardcode.user_middlename_length, blank=True, null=True, verbose_name=_ug('Middle Name')) mothers_name = models.CharField( max_length=hardcode.user_mothersname_length, blank=True, null=True, verbose_name=_ug('Mothers Name')) nickname = models.CharField(max_length=hardcode.user_nickname_length, blank=True, null=True, verbose_name=_ug('Nickname')) skype = models.CharField(max_length=hardcode.user_skype_length, blank=True, null=True, verbose_name=_ug('Skype')) company = models.ForeignKey(Company, related_name='employees', blank=True, null=True, verbose_name=_ug('Company')) supervisor = models.ForeignKey('CustomUser', related_name='subordinates', blank=True, null=True, verbose_name=_ug('Supervisor')) avatar = ThumbnailerImageField(upload_to=hardcode.user_avatar_upload, default=hardcode.user_default_photo, blank=True, null=True, verbose_name=_ug('Profile picture')) birthday = models.DateField(blank=True, null=True, verbose_name=_ug('Birthday')) # gender = models.IntegerField( # default=hardcode.GENDER_UNDEFINED, # choices=hardcode.GENDER, # blank=True, # null=True, # verbose_name=_ug('Gender') # ) edition_date = models.DateTimeField(auto_now=True, verbose_name=_ug('Last edition date')) role = models.ManyToManyField(Role, related_name='customusers', verbose_name=_ug('Custom users')) class Meta: verbose_name = _ug('User') verbose_name_plural = _ug('Users') permissions = ( ('query_customuser', 'Query User'), ('list_customuser', 'List Users'), ) def save(self, *args, **kwargs): if self.pk is None: avatar = self.avatar self.avatar = None super(CustomUser, self).save(*args, **kwargs) self.avatar = avatar super(CustomUser, self).save(*args, **kwargs) def delete(self, *args): if self.active is False: super(CustomUser, self).delete(*args) else: self.active = False self.save() def __str__(self): return "%s - %s %s" % (self.username, self.first_name, self.last_name) def get_full_name(self): full_name = '%s %s %s %s' % (self.first_name, self.middle_name, self.last_name, self.mothers_name) return full_name.strip() def get_username(self): return "%s" % self.username def get_nickname(self): return "%s" % self.nickname def get_short_name(self): if self.nickname is None or self.nickname == '': return "%s" % self.username return self.get_nickname() def is_authorized(self): return self.is_active def is_admin(self): return self.is_staff def is_super(self): return self.is_superuser