Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions partner_programs/services.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,48 @@

from openpyxl.cell.cell import ILLEGAL_CHARACTERS_RE
from django.db.models import Prefetch
from django.utils import timezone

from partner_programs.models import (
PartnerProgram,
PartnerProgramField,
PartnerProgramFieldValue,
PartnerProgramProject,
PartnerProgramUserProfile,
)
from project_rates.models import Criteria, ProjectScore
from projects.models import Project

logger = logging.getLogger()


def publish_finished_program_projects(now=None) -> int:
if now is None:
now = timezone.now()

program_ids = PartnerProgram.objects.filter(
publish_projects_after_finish=True,
datetime_finished__lte=now,
).values_list("id", flat=True)
if not program_ids.exists():
return 0

link_project_ids = PartnerProgramProject.objects.filter(
partner_program_id__in=program_ids
).values_list("project_id", flat=True)
profile_project_ids = PartnerProgramUserProfile.objects.filter(
partner_program_id__in=program_ids,
project_id__isnull=False,
).values_list("project_id", flat=True)
project_ids = link_project_ids.union(profile_project_ids)

return Project.objects.filter(
id__in=project_ids,
is_public=False,
draft=False,
).update(is_public=True)


class ProjectScoreDataPreparer:
"""
Data preparer about project_rates by experts.
Expand Down
13 changes: 13 additions & 0 deletions partner_programs/tasks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import logging

from procollab.celery import app
from partner_programs.services import publish_finished_program_projects

logger = logging.getLogger(__name__)


@app.task
def publish_finished_program_projects_task() -> int:
updated_count = publish_finished_program_projects()
logger.info("Published %s program projects after finish", updated_count)
return updated_count
121 changes: 120 additions & 1 deletion partner_programs/tests.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
from django.contrib.auth import get_user_model
from django.test import TestCase
from django.utils import timezone

from partner_programs.models import PartnerProgram, PartnerProgramField
from partner_programs.models import (
PartnerProgram,
PartnerProgramField,
PartnerProgramProject,
PartnerProgramUserProfile,
)
from partner_programs.serializers import PartnerProgramFieldValueUpdateSerializer
from partner_programs.services import publish_finished_program_projects
from projects.models import Project


class PartnerProgramFieldValueUpdateSerializerInvalidTests(TestCase):
Expand Down Expand Up @@ -118,6 +126,117 @@ def test_file_empty_required(self):
self.assertIn("Файл обязателен для этого поля.", str(serializer.errors))


class PublishFinishedProgramProjectsTests(TestCase):
def setUp(self):
self.now = timezone.now()
self.user = get_user_model().objects.create_user(
email="user@example.com",
password="pass",
first_name="User",
last_name="Test",
birthday="1990-01-01",
)

def create_program(self, **overrides):
defaults = {
"name": "Program",
"tag": "program_tag",
"description": "Program description",
"city": "Moscow",
"image_address": "https://example.com/image.png",
"cover_image_address": "https://example.com/cover.png",
"advertisement_image_address": "https://example.com/advertisement.png",
"presentation_address": "https://example.com/presentation.pdf",
"data_schema": {},
"draft": False,
"projects_availability": "all_users",
"datetime_registration_ends": self.now - timezone.timedelta(days=5),
"datetime_started": self.now - timezone.timedelta(days=30),
"datetime_finished": self.now - timezone.timedelta(days=1),
}
defaults.update(overrides)
return PartnerProgram.objects.create(**defaults)

def create_project(self, **overrides):
defaults = {
"leader": self.user,
"draft": False,
"is_public": False,
"name": "Project",
}
defaults.update(overrides)
return Project.objects.create(**defaults)

def test_publish_updates_projects_from_both_sources(self):
program = self.create_program(publish_projects_after_finish=True)

link_project = self.create_project(name="Linked Project")
PartnerProgramProject.objects.create(
partner_program=program,
project=link_project,
)

profile_project = self.create_project(name="Profile Project")
PartnerProgramUserProfile.objects.create(
user=self.user,
partner_program=program,
project=profile_project,
partner_program_data={},
)

publish_finished_program_projects()

link_project.refresh_from_db()
profile_project.refresh_from_db()
self.assertTrue(link_project.is_public)
self.assertTrue(profile_project.is_public)

def test_publish_skips_draft_projects(self):
program = self.create_program(publish_projects_after_finish=True)
draft_project = self.create_project(draft=True, name="Draft Project")
PartnerProgramProject.objects.create(
partner_program=program,
project=draft_project,
)

publish_finished_program_projects()

draft_project.refresh_from_db()
self.assertFalse(draft_project.is_public)

def test_publish_skips_when_flag_false(self):
program = self.create_program(publish_projects_after_finish=False)
project = self.create_project(name="Private Project")
PartnerProgramProject.objects.create(
partner_program=program,
project=project,
)

publish_finished_program_projects()

project.refresh_from_db()
self.assertFalse(project.is_public)

def test_publish_after_flag_enabled_post_finish(self):
program = self.create_program(publish_projects_after_finish=False)
project = self.create_project(name="Delayed Project")
PartnerProgramProject.objects.create(
partner_program=program,
project=project,
)

publish_finished_program_projects()
project.refresh_from_db()
self.assertFalse(project.is_public)

program.publish_projects_after_finish = True
program.save(update_fields=["publish_projects_after_finish"])

publish_finished_program_projects()
project.refresh_from_db()
self.assertTrue(project.is_public)


class PartnerProgramFieldValueUpdateSerializerValidTests(TestCase):
def setUp(self):
now = timezone.now()
Expand Down
6 changes: 5 additions & 1 deletion procollab/celery.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@
"task": "vacancy.tasks.email_notificate_vacancy_outdated",
# "schedule": crontab(minute=0, hour=0),
"schedule": crontab(minute="*"),
}
},
"publish_finished_program_projects": {
"task": "partner_programs.tasks.publish_finished_program_projects_task",
"schedule": crontab(minute=0, hour=6),
},
}

if __name__ == "__main__":
Expand Down
1 change: 1 addition & 0 deletions procollab/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -418,3 +418,4 @@
CELERY_ACCEPT_CONTENT = ["application/json"]
CELERY_RESULT_SERIALIZER = "json"
CELERY_TASK_SERIALIZER = "json"
CELERY_TIMEZONE = "Europe/Moscow"