Пример #1
0
class Migration(migrations.Migration):

    dependencies = [
        ("contenttypes", "0002_remove_content_type_name"),
        ("profiles", "0007_profile_is_public"),
    ]

    operations = [
        migrations.AlterField(
            model_name="profile",
            name="slug",
            field=sluggable_fields.SluggableField(unique=True),
        ),
        migrations.CreateModel(
            name="ProfileSlug",
            fields=[
                (
                    "id",
                    models.AutoField(
                        auto_created=True,
                        primary_key=True,
                        serialize=False,
                        verbose_name="ID",
                    ),
                ),
                ("object_id", models.PositiveIntegerField()),
                (
                    "slug",
                    models.CharField(db_index=True,
                                     max_length=255,
                                     unique=True,
                                     verbose_name="URL"),
                ),
                (
                    "redirect",
                    models.BooleanField(default=False,
                                        verbose_name="Redirection"),
                ),
                ("created", models.DateTimeField(auto_now_add=True)),
                (
                    "content_type",
                    models.ForeignKey(on_delete=deletion.PROTECT,
                                      to="contenttypes.ContentType"),
                ),
            ],
            options={"abstract": False},
        ),
        migrations.RunPython(code=create_slugs,
                             reverse_code=migrations.RunPython.noop),
    ]
Пример #2
0
class Profile(models.Model):

    user = models.OneToOneField(settings.AUTH_USER_MODEL,
                                on_delete=models.CASCADE)
    slug = sluggable_fields.SluggableField(decider=ProfileSlug,
                                           populate_from="name",
                                           slugify=slugify_user,
                                           unique=True)
    is_public = models.BooleanField(default=True)
    is_approved = models.BooleanField(default=False)
    name = models.CharField(max_length=200,
                            validators=[validate_sluggable_name])
    image = thumbnail.ImageField(
        upload_to=upload_path.auto_cleaned_path_stripped_uuid4, blank=True)
    city_or_town = models.CharField(max_length=100, blank=True)
    country = models.CharField(max_length=100, blank=True)
    linkedin_url = models.URLField(max_length=400, blank=True)
    facebook_url = models.URLField(max_length=400, blank=True)
    personal_website_url = models.URLField(max_length=400, blank=True)
    lat = models.FloatField(null=True, blank=True, default=None)
    lon = models.FloatField(null=True, blank=True, default=None)
    cause_areas = postgres_fields.ArrayField(enum.EnumField(CauseArea),
                                             blank=True,
                                             default=list)
    cause_areas_other = models.TextField(blank=True,
                                         validators=[MaxLengthValidator(2000)])
    available_to_volunteer = models.BooleanField(null=True,
                                                 blank=True,
                                                 default=None)
    open_to_job_offers = models.BooleanField(null=True,
                                             blank=True,
                                             default=None)
    expertise_areas = postgres_fields.ArrayField(enum.EnumField(ExpertiseArea),
                                                 blank=True,
                                                 default=list)
    expertise_areas_other = models.TextField(
        blank=True, validators=[MaxLengthValidator(2000)])
    career_interest_areas = postgres_fields.ArrayField(
        enum.EnumField(ExpertiseArea), blank=True, default=list)
    available_as_speaker = models.BooleanField(null=True,
                                               blank=True,
                                               default=None)
    email_visible = models.BooleanField(default=False)
    topics_i_speak_about = models.TextField(
        blank=True, validators=[MaxLengthValidator(2000)])
    organisational_affiliations = postgres_fields.ArrayField(
        enum.EnumField(OrganisationalAffiliation), blank=True, default=list)
    summary = models.TextField(blank=True,
                               validators=[MaxLengthValidator(2000)])
    giving_pledges = postgres_fields.ArrayField(enum.EnumField(GivingPledge),
                                                blank=True,
                                                default=list)
    local_groups = models.ManyToManyField(LocalGroup,
                                          through="Membership",
                                          blank=True)
    legacy_record = models.PositiveIntegerField(null=True,
                                                default=None,
                                                editable=False,
                                                unique=True)
    offering = models.TextField(blank=True,
                                validators=[MaxLengthValidator(2000)])
    looking_for = models.TextField(blank=True,
                                   validators=[MaxLengthValidator(2000)])

    slugs = contenttypes_fields.GenericRelation(ProfileSlug)

    objects = ProfileManager()

    class Meta:
        ordering = ["name", "slug"]

    def __str__(self):
        return self.name

    def is_searchable(self) -> bool:
        return self.is_approved and self.is_public and self.user.is_active

    def get_absolute_url(self):
        return urls.reverse("profile", args=[self.slug])

    def get_email_searchable(self) -> Optional[str]:
        return self.user.email if self.email_visible else None

    def geocode(self):
        self.lat = None
        self.lon = None
        if self.city_or_town and self.country:
            geocoders.options.default_user_agent = "eahub"
            location = geocoders.Nominatim(
                timeout=10).geocode(f"{self.city_or_town}, {self.country}")
            if location:
                self.lat = location.latitude
                self.lon = location.longitude
        return self

    def get_pretty_cause_areas(self):
        return prettify_property_list(CauseArea, self.cause_areas,
                                      self.cause_areas_other)

    def get_image_url(self) -> Optional[str]:
        if self.image:
            return get_thumbnail(self.image, "200x200", crop="center").url
        else:
            return None

    # todo rename to get_list something
    def get_cause_areas_searchable(self) -> List[str]:
        return self._format_enum_array_for_searching(self.cause_areas,
                                                     CauseArea)

    def get_pretty_expertise(self):
        return prettify_property_list(ExpertiseArea, self.expertise_areas,
                                      self.expertise_areas_other)

    def get_expertise_searchable(self) -> List[str]:
        return self._format_enum_array_for_searching(self.expertise_areas,
                                                     ExpertiseArea)

    def get_pretty_career_interest_areas(self):
        return prettify_property_list(ExpertiseArea,
                                      self.career_interest_areas)

    def get_career_interest_areas_searchable(self) -> List[str]:
        return self._format_enum_array_for_searching(
            self.career_interest_areas, ExpertiseArea)

    def get_pretty_giving_pledges(self):
        if self.giving_pledges:
            return ", ".join(map(GivingPledge.label, self.giving_pledges))
        else:
            return "N/A"

    def get_giving_pledges_searchable(self) -> List[str]:
        return self._format_enum_array_for_searching(self.giving_pledges,
                                                     GivingPledge)

    def get_pretty_organisational_affiliations(self):
        if self.organisational_affiliations:
            return ", ".join(
                map(OrganisationalAffiliation.label,
                    self.organisational_affiliations))
        else:
            return "N/A"

    def get_organisational_affiliations_searchable(self) -> List[str]:
        return self._format_enum_array_for_searching(
            self.organisational_affiliations, OrganisationalAffiliation)

    def get_pretty_local_groups(self):
        if self.local_groups:
            return ", ".join(self.get_local_groups_searchable())
        else:
            return "N/A"

    def get_local_groups_searchable(self) -> List[str]:
        return [f"{group.name}" for group in self.local_groups.all()]

    def get_organizer_of_local_groups_searchable(self) -> List[str]:
        return [f"{group.name}" for group in self.user.localgroup_set.all()]

    def write_data_export_zip(self, request, response):
        with zipfile.ZipFile(response, mode="w") as zip_file:
            with zip_file.open(f"{self.slug}.json",
                               mode="w") as json_binary_file, io.TextIOWrapper(
                                   json_binary_file) as json_file:
                json.dump(
                    {
                        "email":
                        self.user.email,
                        "date_joined":
                        self.user.date_joined.isoformat(),
                        "last_login":
                        self.user.last_login.isoformat(),
                        "url":
                        request.build_absolute_uri(self.get_absolute_url()),
                        "is_public":
                        self.is_public,
                        "is_approved":
                        self.is_approved,
                        "name":
                        self.name,
                        "city_or_town":
                        self.city_or_town,
                        "country":
                        self.country,
                        "cause_areas":
                        list(map(CauseArea.label, self.cause_areas)),
                        "cause_areas_other":
                        self.cause_areas_other,
                        "available_to_volunteer":
                        self.available_to_volunteer,
                        "open_to_job_offers":
                        self.open_to_job_offers,
                        "expertise_areas":
                        list(map(ExpertiseArea.label, self.expertise_areas)),
                        "expertise_areas_other":
                        self.expertise_areas_other,
                        "career_interest_areas":
                        list(
                            map(ExpertiseArea.label,
                                self.career_interest_areas)),
                        "available_as_speaker":
                        self.available_as_speaker,
                        "topics_i_speak_about":
                        self.topics_i_speak_about,
                        "organisational_affiliations":
                        list(
                            map(
                                OrganisationalAffiliation.label,
                                self.organisational_affiliations,
                            )),
                        "summary":
                        self.summary,
                        "giving_pledges":
                        list(map(GivingPledge.label, self.giving_pledges)),
                        "member_of_local_groups": [
                            request.build_absolute_uri(
                                local_group.get_absolute_url())
                            for local_group in self.local_groups.all()
                        ],
                        "organiser_of_local_groups": [
                            request.build_absolute_uri(
                                local_group.get_absolute_url())
                            for local_group in self.user.localgroup_set.all()
                        ],
                        "aliases": [
                            request.build_absolute_uri(
                                urls.reverse("profile",
                                             kwargs={"slug": slug.slug}))
                            for slug in self.slugs.filter(redirect=True)
                        ],
                        "legacy_hub_url":
                        (self.legacy_record and request.build_absolute_uri(
                            urls.reverse(
                                "profile_legacy",
                                kwargs={"legacy_record": self.legacy_record},
                            ))),
                    },
                    json_file,
                    indent=2,
                )
            if self.image:
                with self.image.open() as image_src_file, zip_file.open(
                        self.slug + pathlib.PurePath(self.image.name).suffix,
                        mode="w") as image_dst_file:
                    shutil.copyfileobj(image_src_file, image_dst_file)

    def image_placeholder(self):
        return f"Avatar{self.id % 10}.jpg"

    def has_cause_area_details(self):
        cause_area_details_exist = [
            len(self.cause_areas) > 0,
            len(self.cause_areas_other) > 0,
            len(self.giving_pledges) > 0,
            self.available_to_volunteer,
        ]
        return any(cause_area_details_exist)

    def has_career_details(self):
        career_details_exist = [
            len(self.expertise_areas),
            len(self.expertise_areas_other),
            self.open_to_job_offers,
        ]
        return any(career_details_exist)

    def has_community_details(self):
        community_details_exist = [
            len(self.organisational_affiliations) > 0,
            self.local_groups.exists(),
            self.user.localgroup_set.exists(), self.available_as_speaker,
            len(self.topics_i_speak_about) > 0, self.offering, self.looking_for
        ]
        return any(community_details_exist)

    def get_is_organiser(self):
        return self.user.localgroup_set.exists()

    def convert_to_row(self, field_names):
        values = []
        for field in field_names:
            if "_other" in field:
                continue
            elif field == "cause_areas":
                values.append(self.get_pretty_cause_areas())
            elif field == "expertise_areas":
                values.append(self.get_pretty_expertise())
            elif field == "career_interest_areas":
                values.append(self.get_pretty_career_interest_areas())
            elif field == "organisational_affiliations":
                values.append(self.get_pretty_organisational_affiliations())
            elif field == "giving_pledges":
                values.append(self.get_pretty_giving_pledges())
            elif field == "local_groups":
                values.append(self.get_pretty_local_groups())
            else:
                values.append(getattr(self, field))
        return values

    def _format_enum_array_for_searching(self, enum_values_list: List[Union[
        enum.Enum, str, int]], enum_cls: enum.Enum) -> List[str]:
        enum_labels: List[str] = []
        for enum_value_raw in enum_values_list:
            enum_value = int(enum_value_raw)
            enum_labels.append(enum_cls.values[enum_value].label)
        return enum_labels

    @staticmethod
    def get_exportable_field_names():
        return [
            field.name
            for field in Profile._meta.fields + Profile._meta.many_to_many
            if "_other" not in field.name
        ]
Пример #3
0
class Profile(models.Model):

    user = models.OneToOneField(settings.AUTH_USER_MODEL,
                                on_delete=models.CASCADE)
    slug = sluggable_fields.SluggableField(decider=ProfileSlug,
                                           populate_from="name",
                                           slugify=slugify_user,
                                           unique=True)
    is_public = models.BooleanField(default=True)
    name = models.CharField(max_length=200,
                            validators=[validate_sluggable_name])
    image = thumbnail.ImageField(
        upload_to=upload_path.auto_cleaned_path_stripped_uuid4, blank=True)
    city_or_town = models.CharField(max_length=100, blank=True)
    country = models.CharField(max_length=100, blank=True)
    lat = models.FloatField(null=True, blank=True, default=None)
    lon = models.FloatField(null=True, blank=True, default=None)
    cause_areas = postgres_fields.ArrayField(enum.EnumField(CauseArea),
                                             blank=True,
                                             default=list)
    cause_areas_other = models.TextField(blank=True)
    available_to_volunteer = models.BooleanField(null=True,
                                                 blank=True,
                                                 default=None)
    open_to_job_offers = models.BooleanField(null=True,
                                             blank=True,
                                             default=None)
    expertise_areas = postgres_fields.ArrayField(enum.EnumField(ExpertiseArea),
                                                 blank=True,
                                                 default=list)
    expertise_areas_other = models.TextField(blank=True)
    available_as_speaker = models.BooleanField(null=True,
                                               blank=True,
                                               default=None)
    topics_i_speak_about = models.TextField(blank=True)
    organisational_affiliations = postgres_fields.ArrayField(
        enum.EnumField(OrganisationalAffiliation), blank=True, default=list)
    summary = models.TextField(blank=True)
    giving_pledges = postgres_fields.ArrayField(enum.EnumField(GivingPledge),
                                                blank=True,
                                                default=list)
    local_groups = models.ManyToManyField(LocalGroup,
                                          through="Membership",
                                          blank=True)
    legacy_record = models.PositiveIntegerField(null=True,
                                                default=None,
                                                editable=False,
                                                unique=True)

    slugs = contenttypes_fields.GenericRelation(ProfileSlug)

    objects = ProfileManager()

    class Meta:
        ordering = ["name", "slug"]

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return urls.reverse("profile", args=[self.slug])

    def geocode(self):
        self.lat = None
        self.lon = None
        if self.city_or_town and self.country:
            location = geocoders.Nominatim(
                timeout=10).geocode(f"{self.city_or_town}, {self.country}")
            if location:
                self.lat = location.latitude
                self.lon = location.longitude
        return self

    def get_pretty_cause_areas(self):
        return prettify_property_list(CauseArea, self.cause_areas,
                                      self.cause_areas_other)

    def get_pretty_expertise(self):
        return prettify_property_list(ExpertiseArea, self.expertise_areas,
                                      self.expertise_areas_other)

    def get_pretty_giving_pledges(self):
        if self.giving_pledges:
            return ", ".join(map(GivingPledge.label, self.giving_pledges))
        else:
            return "N/A"

    def get_pretty_organisational_affiliations(self):
        if self.organisational_affiliations:
            return ", ".join(
                map(OrganisationalAffiliation.label,
                    self.organisational_affiliations))
        else:
            return "N/A"

    def get_pretty_local_groups(self):
        if self.local_groups:
            return ", ".join([
                "{local_group}".format(local_group=x.name)
                for x in self.local_groups.all()
            ])
        else:
            return "N/A"

    def write_data_export_zip(self, request, response):
        with zipfile.ZipFile(response, mode="w") as zip_file:
            with zip_file.open(f"{self.slug}.json",
                               mode="w") as json_binary_file, io.TextIOWrapper(
                                   json_binary_file) as json_file:
                json.dump(
                    {
                        "email":
                        self.user.email,
                        "date_joined":
                        self.user.date_joined.isoformat(),
                        "last_login":
                        self.user.last_login.isoformat(),
                        "url":
                        request.build_absolute_uri(self.get_absolute_url()),
                        "is_public":
                        self.is_public,
                        "name":
                        self.name,
                        "city_or_town":
                        self.city_or_town,
                        "country":
                        self.country,
                        "cause_areas":
                        list(map(CauseArea.label, self.cause_areas)),
                        "cause_areas_other":
                        self.cause_areas_other,
                        "available_to_volunteer":
                        self.available_to_volunteer,
                        "open_to_job_offers":
                        self.open_to_job_offers,
                        "expertise_areas":
                        list(map(ExpertiseArea.label, self.expertise_areas)),
                        "expertise_areas_other":
                        self.expertise_areas_other,
                        "available_as_speaker":
                        self.available_as_speaker,
                        "topics_i_speak_about":
                        self.topics_i_speak_about,
                        "organisational_affiliations":
                        list(
                            map(
                                OrganisationalAffiliation.label,
                                self.organisational_affiliations,
                            )),
                        "summary":
                        self.summary,
                        "giving_pledges":
                        list(map(GivingPledge.label, self.giving_pledges)),
                        "member_of_local_groups": [
                            request.build_absolute_uri(
                                local_group.get_absolute_uri())
                            for local_group in self.local_groups.all()
                        ],
                        "organiser_of_local_groups": [
                            request.build_absolute_uri(
                                local_group.get_absolute_uri())
                            for local_group in self.user.localgroup_set.all()
                        ],
                        "aliases": [
                            request.build_absolute_uri(
                                urls.reverse("profile",
                                             kwargs={"slug": slug.slug}))
                            for slug in self.slugs.filter(redirect=True)
                        ],
                        "legacy_hub_url":
                        (self.legacy_record and request.build_absolute_uri(
                            urls.reverse(
                                "profile_legacy",
                                kwargs={"legacy_record": self.legacy_record},
                            ))),
                    },
                    json_file,
                    indent=2,
                )
            if self.image:
                with self.image.open() as image_src_file, zip_file.open(
                        self.slug + pathlib.PurePath(self.image.name).suffix,
                        mode="w") as image_dst_file:
                    shutil.copyfileobj(image_src_file, image_dst_file)

    def image_placeholder(self):
        return f"Avatar{self.id % 10}.png"

    def has_cause_area_details(self):
        cause_area_details_exist = [
            len(self.cause_areas) > 0,
            len(self.cause_areas_other) > 0,
            len(self.giving_pledges) > 0,
            self.available_to_volunteer,
        ]
        return any(cause_area_details_exist)

    def has_career_details(self):
        career_details_exist = [
            len(self.expertise_areas),
            len(self.expertise_areas_other),
            self.open_to_job_offers,
        ]
        return any(career_details_exist)

    def has_community_details(self):
        community_details_exist = [
            len(self.organisational_affiliations) > 0,
            self.local_groups.exists(),
            self.user.localgroup_set.exists(),
            self.available_as_speaker,
            len(self.topics_i_speak_about) > 0,
        ]
        return any(community_details_exist)