diff --git a/apps/news/models.py b/apps/news/models.py index b24d442d..8924474a 100644 --- a/apps/news/models.py +++ b/apps/news/models.py @@ -24,6 +24,8 @@ from utils.models import ( TJSONField, TranslatedFieldsMixin, TypeDefaultImageMixin, CarouselMixin) from utils.querysets import TranslationQuerysetMixin +from location.models import Country +from utils.parsers import NewsSlug class Agenda(ProjectBaseMixin, TranslatedFieldsMixin): @@ -362,9 +364,36 @@ class News(GalleryMixin, return f'news: {next(iter(self.slugs.values()))}' def create_duplicate(self, new_country, view_count_model): + country_codes = list(Country.objects.all().values_list('code', flat=True)) + + # Get all existed slugs + all_slugs = {slug_value + for slug_dict in News.objects.all().values_list('slugs', flat=True) + for slug_value in slug_dict.values()} + + new_slugs = {} + for locale, raw_slug in self.slugs.items(): + slug = NewsSlug.parse(raw_slug, country_codes) + + # all slugs LIKE% slug + similar_slugs = sorted(x for x in all_slugs if NewsSlug.parse(x, country_codes).value == slug.value) + + if len(similar_slugs) == 0: + # It is impossible because at least current instance has slug + raise ValueError('Duplicating unsaved object') + else: + # The last slug in similar_slugs is slug with largest count + last_slug = NewsSlug.parse(similar_slugs[-1], country_codes) + + new_slug = NewsSlug(slug.value, new_country.code, last_slug.count) + if last_slug.country_code is not None: + new_slug.count += 1 + + new_slugs[locale] = str(new_slug) + self.pk = None self.state = self.UNPUBLISHED - self.slugs = {locale: f'{slug}-{new_country.code}' for locale, slug in self.slugs.items()} + self.slugs = new_slugs self.country = new_country self.views_count = view_count_model self.duplication_date = timezone.now() diff --git a/apps/utils/parsers.py b/apps/utils/parsers.py new file mode 100644 index 00000000..dc84a60e --- /dev/null +++ b/apps/utils/parsers.py @@ -0,0 +1,49 @@ + + +class NewsSlug: + def __init__(self, value=None, country_code=None, count=0): + self.value = value + self.country_code = country_code + self.count = count + + @classmethod + def parse(cls, raw_slug, country_codes): + slug, *rest = raw_slug.split('-') + instance = NewsSlug() + + if len(rest) >= 1 and rest[-1] in country_codes: + # It is like 'slug-en' + + instance.value = '-'.join([slug, *rest[:-1]]) + instance.country_code = rest[-1] + elif len(rest) >= 2 and rest[-1].isdigit() and rest[-2] in country_codes: + # It is like 'slug-en-1' + + instance.value = '-'.join([slug, *rest[:-2]]) + instance.country_code = rest[-2] + instance.count = int(rest[-1]) + else: + # It is like 'slug' + + instance.value = '-'.join([slug, *rest]) + + return instance + + def __lt__(self, other): + return self.value < other.value + + def __str__(self): + if self.value is None: + raise ValueError('No value for slug') + + slug_parts = [self.value] + if self.country_code is not None: + slug_parts.append(self.country_code) + + if self.count != 0: + slug_parts.append(str(self.count)) + + return '-'.join(slug_parts) + + def __repr__(self): + return f'<{self.__class__.__name__} {self.value}, {self.country_code}, {self.count}>'