diff --git a/candidates/models.py b/candidates/models.py index 50e90bb..d8e03e5 100644 --- a/candidates/models.py +++ b/candidates/models.py @@ -1,13 +1,13 @@ from django.conf import settings from django.core.validators import FileExtensionValidator from django.db import models - from company.models import Company from offer.models import JobOffer from users.models import UserAccount +from utils.base_model import BaseModel -class Candidate(models.Model): +class Candidate(BaseModel): STATUS = ( ("PENDING", "PENDING"), ("ACCEPTED", "ACCEPTED"), @@ -20,8 +20,6 @@ class Candidate(models.Model): phone = models.CharField(max_length=20) future_recruitment = models.BooleanField(default=False) message = models.TextField(max_length=500, blank=True, null=True) - created_at = models.DateTimeField(auto_now_add=True) - updated_at = models.DateTimeField(auto_now=True) job_offer = models.ForeignKey(JobOffer, on_delete=models.CASCADE) user = models.ForeignKey(UserAccount, on_delete=models.CASCADE, blank=True, null=True) status = models.CharField(max_length=10, choices=STATUS, default="PENDING") diff --git a/company/migrations/0007_company_updated_at_companycategory_created_at_and_more.py b/company/migrations/0007_company_updated_at_companycategory_created_at_and_more.py new file mode 100644 index 0000000..3905f12 --- /dev/null +++ b/company/migrations/0007_company_updated_at_companycategory_created_at_and_more.py @@ -0,0 +1,30 @@ +# Generated by Django 5.0 on 2024-02-27 21:37 + +import django.utils.timezone +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('company', '0006_company_category'), + ] + + operations = [ + migrations.AddField( + model_name='company', + name='updated_at', + field=models.DateTimeField(auto_now=True), + ), + migrations.AddField( + model_name='companycategory', + name='created_at', + field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now), + preserve_default=False, + ), + migrations.AddField( + model_name='companycategory', + name='updated_at', + field=models.DateTimeField(auto_now=True), + ), + ] diff --git a/company/models.py b/company/models.py index a549834..166bd99 100644 --- a/company/models.py +++ b/company/models.py @@ -5,9 +5,10 @@ from company.utils.validate_file_size import validate_file_size from location.models import Address from users.models import UserAccount +from utils.base_model import BaseModel -class CompanyCategory(models.Model): +class CompanyCategory(BaseModel): name = models.CharField(max_length=50) def __str__(self) -> str: @@ -19,7 +20,7 @@ class Meta: ordering = ['name'] -class Company(models.Model): +class Company(BaseModel): name = models.CharField(max_length=255) slug = models.SlugField(max_length=200, unique=True, blank=True) category = models.ForeignKey(CompanyCategory, on_delete=models.CASCADE, null=True, blank=True) @@ -46,7 +47,6 @@ class Company(models.Model): instagram_url = models.URLField(null=True, blank=True) youtube_url = models.URLField(null=True, blank=True) website_url = models.URLField(null=True, blank=True) - created_at = models.DateTimeField(auto_now_add=True) is_active = models.BooleanField(default=False) def __str__(self) -> str: diff --git a/favourite/migrations/0003_favourite_updated_at.py b/favourite/migrations/0003_favourite_updated_at.py new file mode 100644 index 0000000..b7a9a81 --- /dev/null +++ b/favourite/migrations/0003_favourite_updated_at.py @@ -0,0 +1,18 @@ +# Generated by Django 5.0 on 2024-02-27 21:37 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('favourite', '0002_initial'), + ] + + operations = [ + migrations.AddField( + model_name='favourite', + name='updated_at', + field=models.DateTimeField(auto_now=True), + ), + ] diff --git a/favourite/models.py b/favourite/models.py index 7785957..3aaa080 100644 --- a/favourite/models.py +++ b/favourite/models.py @@ -2,12 +2,12 @@ from offer.models import JobOffer from users.models import UserAccount +from utils.base_model import BaseModel -class Favourite(models.Model): +class Favourite(BaseModel): user = models.ForeignKey(UserAccount, on_delete=models.CASCADE) offer = models.ForeignKey(JobOffer, on_delete=models.CASCADE) - created_at = models.DateTimeField(auto_now_add=True) def __str__(self): return f"{self.user} {self.offer}" diff --git a/favourite/urls.py b/favourite/urls.py index 7211936..116e26e 100644 --- a/favourite/urls.py +++ b/favourite/urls.py @@ -1,10 +1,11 @@ from django.urls import path from .views import ( - FavouriteAPIView, + FavouriteListCreateAPIView, + FavouriteDeleteAPIView ) urlpatterns = [ - path("", FavouriteAPIView.as_view(), name="favourite_list_create_delete"), - + path("", FavouriteListCreateAPIView.as_view(), name="favourite_list_create_delete"), + path("/", FavouriteDeleteAPIView.as_view(), name="favourite_delete_by_id") ] diff --git a/favourite/views.py b/favourite/views.py index 7f2c60f..58f7767 100644 --- a/favourite/views.py +++ b/favourite/views.py @@ -12,7 +12,7 @@ from .services.favourite import FavouriteService -class FavouriteAPIView(APIView): +class FavouriteListCreateAPIView(APIView): """ API view for handling Favourite operations. @@ -53,6 +53,11 @@ def post(self, request): self._service.create(serializer.validated_data) return Response(serializer.data, status=status.HTTP_201_CREATED) + +class FavouriteDeleteAPIView(APIView): + permission_classes = (IsAuthenticated,) + _service = FavouriteService(FavouriteRepository()) + def delete(self, request, pk): """ Handles the HTTP DELETE request to delete a favourite. diff --git a/location/migrations/0003_address_created_at_address_updated_at_and_more.py b/location/migrations/0003_address_created_at_address_updated_at_and_more.py new file mode 100644 index 0000000..92ba1b4 --- /dev/null +++ b/location/migrations/0003_address_created_at_address_updated_at_and_more.py @@ -0,0 +1,58 @@ +# Generated by Django 5.0 on 2024-02-27 21:37 + +import django.utils.timezone +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('location', '0002_alter_address_city_alter_address_country_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='address', + name='created_at', + field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now), + preserve_default=False, + ), + migrations.AddField( + model_name='address', + name='updated_at', + field=models.DateTimeField(auto_now=True), + ), + migrations.AddField( + model_name='city', + name='created_at', + field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now), + preserve_default=False, + ), + migrations.AddField( + model_name='city', + name='updated_at', + field=models.DateTimeField(auto_now=True), + ), + migrations.AddField( + model_name='country', + name='created_at', + field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now), + preserve_default=False, + ), + migrations.AddField( + model_name='country', + name='updated_at', + field=models.DateTimeField(auto_now=True), + ), + migrations.AddField( + model_name='region', + name='created_at', + field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now), + preserve_default=False, + ), + migrations.AddField( + model_name='region', + name='updated_at', + field=models.DateTimeField(auto_now=True), + ), + ] diff --git a/location/models.py b/location/models.py index c0d3ab9..31ca32f 100644 --- a/location/models.py +++ b/location/models.py @@ -1,7 +1,8 @@ from django.db import models +from utils.base_model import BaseModel -class Country(models.Model): +class Country(BaseModel): name = models.CharField(max_length=255) def __str__(self): @@ -13,7 +14,7 @@ class Meta: verbose_name_plural = "Countries" -class Region(models.Model): +class Region(BaseModel): name = models.CharField(max_length=255) country = models.ForeignKey(Country, on_delete=models.CASCADE) @@ -26,7 +27,7 @@ class Meta: verbose_name_plural = "Regions" -class City(models.Model): +class City(BaseModel): name = models.CharField(max_length=255) region = models.ForeignKey(Region, on_delete=models.CASCADE, null=True, blank=True) country = models.ForeignKey(Country, on_delete=models.CASCADE, null=True, blank=True) @@ -42,7 +43,7 @@ class Meta: verbose_name_plural = "Cities" -class Address(models.Model): +class Address(BaseModel): country = models.ForeignKey(Country, on_delete=models.CASCADE, null=True, blank=True) city = models.ForeignKey(City, on_delete=models.CASCADE, null=True, blank=True) region = models.ForeignKey(Region, on_delete=models.CASCADE, null=True, blank=True) diff --git a/offer/migrations/0006_employmenttype_created_at_employmenttype_updated_at_and_more.py b/offer/migrations/0006_employmenttype_created_at_employmenttype_updated_at_and_more.py new file mode 100644 index 0000000..3f7a661 --- /dev/null +++ b/offer/migrations/0006_employmenttype_created_at_employmenttype_updated_at_and_more.py @@ -0,0 +1,69 @@ +# Generated by Django 5.0 on 2024-02-27 21:37 + +import django.utils.timezone +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('offer', '0005_alter_jobofferrate_options_jobofferrate_created_at'), + ] + + operations = [ + migrations.AddField( + model_name='employmenttype', + name='created_at', + field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now), + preserve_default=False, + ), + migrations.AddField( + model_name='employmenttype', + name='updated_at', + field=models.DateTimeField(auto_now=True), + ), + migrations.AddField( + model_name='experience', + name='created_at', + field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now), + preserve_default=False, + ), + migrations.AddField( + model_name='experience', + name='updated_at', + field=models.DateTimeField(auto_now=True), + ), + migrations.AddField( + model_name='jobofferrate', + name='updated_at', + field=models.DateTimeField(auto_now=True), + ), + migrations.AddField( + model_name='salary', + name='created_at', + field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now), + preserve_default=False, + ), + migrations.AddField( + model_name='salary', + name='updated_at', + field=models.DateTimeField(auto_now=True), + ), + migrations.AddField( + model_name='worktype', + name='created_at', + field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now), + preserve_default=False, + ), + migrations.AddField( + model_name='worktype', + name='updated_at', + field=models.DateTimeField(auto_now=True), + ), + migrations.AlterField( + model_name='jobofferrate', + name='created_at', + field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now), + preserve_default=False, + ), + ] diff --git a/offer/models.py b/offer/models.py index dcf750f..09a2287 100644 --- a/offer/models.py +++ b/offer/models.py @@ -5,9 +5,10 @@ from company.models import Company from location.models import Address +from utils.base_model import BaseModel -class WorkType(models.Model): +class WorkType(BaseModel): name = models.CharField(max_length=50, unique=True) def __str__(self): @@ -19,7 +20,7 @@ class Meta: verbose_name_plural = 'Work Types' -class EmploymentType(models.Model): +class EmploymentType(BaseModel): name = models.CharField(max_length=50, unique=True) def __str__(self): @@ -31,7 +32,7 @@ class Meta: verbose_name_plural = 'Employment Types' -class Experience(models.Model): +class Experience(BaseModel): name = models.CharField(max_length=50, unique=True) def __str__(self): @@ -43,7 +44,7 @@ class Meta: verbose_name_plural = 'Experiences' -class Salary(models.Model): +class Salary(BaseModel): CURRENCIES = ( ('PLN', 'PLN'), ('EURO', 'EURO'), @@ -71,7 +72,7 @@ class Meta: verbose_name_plural = 'Salaries' -class JobOffer(models.Model): +class JobOffer(BaseModel): STATUS = ( ("DRAFT", "DRAFT"), ("PENDING", "PENDING"), @@ -93,8 +94,6 @@ class JobOffer(models.Model): experience = models.ManyToManyField(Experience, blank=True) work_type = models.ManyToManyField(WorkType, blank=True) employment_type = models.ManyToManyField(EmploymentType, blank=True) - created_at = models.DateTimeField(auto_now_add=True) - updated_at = models.DateTimeField(auto_now=True) status = models.CharField(max_length=10, choices=STATUS, default="DRAFT") # These fields are only used for job offers that are scraped from other websites @@ -130,7 +129,7 @@ def __str__(self) -> str: return self.title -class JobOfferRate(models.Model): +class JobOfferRate(BaseModel): RATE = ( (1, 1), (2, 2), @@ -140,7 +139,6 @@ class JobOfferRate(models.Model): ) job_offer = models.ForeignKey(JobOffer, on_delete=models.CASCADE) rate = models.IntegerField(choices=RATE) - created_at = models.DateTimeField(auto_now_add=True, null=True) def __str__(self) -> str: return f"{self.job_offer} - {self.rate}" diff --git a/payment/models.py b/payment/models.py index ef2b1bd..1f6e7f0 100644 --- a/payment/models.py +++ b/payment/models.py @@ -2,9 +2,10 @@ from company.models import Company from users.models import UserAccount +from utils.base_model import BaseModel -class Product(models.Model): +class Product(BaseModel): TYPES = ( ("NEW_COMPANY", "NEW_COMPANY"), ("NEW_OFFER", "NEW_OFFER") @@ -14,8 +15,6 @@ class Product(models.Model): value = models.IntegerField(default=1) price_euro = models.DecimalField(max_digits=10, decimal_places=2) price_euro_id = models.CharField(max_length=500) - created_at = models.DateTimeField(auto_now_add=True) - updated_at = models.DateTimeField(auto_now=True) def __str__(self): return f"{self.name} {self.value}" @@ -26,13 +25,11 @@ class Meta: verbose_name_plural = "Products" -class PaymentInfo(models.Model): +class PaymentInfo(BaseModel): user = models.ForeignKey(UserAccount, on_delete=models.CASCADE) product = models.ForeignKey(Product, on_delete=models.CASCADE) payment_bool = models.BooleanField(default=False) stripe_checkout_id = models.CharField(max_length=500) - created_at = models.DateTimeField(auto_now_add=True) - updated_at = models.DateTimeField(auto_now=True) def __str__(self): return f"{self.user} {self.product} {self.payment_bool}" diff --git a/support/migrations/0004_contact_updated_at_report_updated_at.py b/support/migrations/0004_contact_updated_at_report_updated_at.py new file mode 100644 index 0000000..59417fb --- /dev/null +++ b/support/migrations/0004_contact_updated_at_report_updated_at.py @@ -0,0 +1,23 @@ +# Generated by Django 5.0 on 2024-02-27 21:37 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('support', '0003_alter_contact_options_alter_report_options'), + ] + + operations = [ + migrations.AddField( + model_name='contact', + name='updated_at', + field=models.DateTimeField(auto_now=True), + ), + migrations.AddField( + model_name='report', + name='updated_at', + field=models.DateTimeField(auto_now=True), + ), + ] diff --git a/support/models.py b/support/models.py index 4fa924d..d27cf40 100644 --- a/support/models.py +++ b/support/models.py @@ -1,18 +1,15 @@ -from datetime import timedelta - from django.db import models -from django.utils import timezone +from utils.base_model import BaseModel from offer.models import JobOffer from users.models import UserAccount -class Contact(models.Model): +class Contact(BaseModel): subject = models.CharField(max_length=50) message = models.TextField(max_length=500) email = models.EmailField() reviewed = models.BooleanField(default=False) - created_at = models.DateTimeField(auto_now_add=True) def __str__(self): return self.subject @@ -23,12 +20,11 @@ class Meta: verbose_name_plural = 'Contacts' -class Report(models.Model): +class Report(BaseModel): user = models.ForeignKey(UserAccount, on_delete=models.CASCADE) offer = models.ForeignKey(JobOffer, on_delete=models.CASCADE) description = models.CharField(max_length=255) reviewed = models.BooleanField(default=False) - created_at = models.DateTimeField(auto_now_add=True) def __str__(self): return self.description diff --git a/tests/test_favourite/test_views.py b/tests/test_favourite/test_views.py index 3175206..7a9057b 100644 --- a/tests/test_favourite/test_views.py +++ b/tests/test_favourite/test_views.py @@ -4,7 +4,7 @@ from rest_framework.test import force_authenticate, APIRequestFactory from favourite.models import Favourite -from favourite.views import FavouriteAPIView +from favourite.views import FavouriteListCreateAPIView, FavouriteDeleteAPIView from tests.fixtures import job_offer, user factory = APIRequestFactory() @@ -12,7 +12,7 @@ @pytest.mark.django_db def test_success_return_list_of_favourite_job_offers_for_specified_user(user, job_offer): - view = FavouriteAPIView.as_view() + view = FavouriteListCreateAPIView.as_view() Favourite.objects.create(offer=job_offer, user=user) request = factory.get('/api/favourite/') force_authenticate(request, user=user) @@ -23,7 +23,7 @@ def test_success_return_list_of_favourite_job_offers_for_specified_user(user, jo @pytest.mark.django_db def test_error_list_of_favourite_job_offers_not_authenticated(user, job_offer): - view = FavouriteAPIView.as_view() + view = FavouriteListCreateAPIView.as_view() Favourite.objects.create(offer=job_offer, user=user) request = factory.get('/api/favourite/') response = view(request) @@ -32,7 +32,7 @@ def test_error_list_of_favourite_job_offers_not_authenticated(user, job_offer): @pytest.mark.django_db def test_success_create_favourite_job_offer_for_specified_user(user, job_offer): - view = FavouriteAPIView.as_view() + view = FavouriteListCreateAPIView.as_view() data = json.dumps({"offer_id": 1, "offer": 1, "user": user.id}) @@ -44,7 +44,7 @@ def test_success_create_favourite_job_offer_for_specified_user(user, job_offer): @pytest.mark.django_db def test_error_create_favourite_job_offer_for_not_authenticated_user(user, job_offer): - view = FavouriteAPIView.as_view() + view = FavouriteListCreateAPIView.as_view() data = json.dumps({"offer_id": 1, "offer": 1, "user": user.id}) @@ -55,7 +55,7 @@ def test_error_create_favourite_job_offer_for_not_authenticated_user(user, job_o @pytest.mark.django_db def test_error_create_favourite_job_offer_already_saved(user, job_offer): - view = FavouriteAPIView.as_view() + view = FavouriteListCreateAPIView.as_view() Favourite.objects.create(offer=job_offer, user=user) data = json.dumps({"offer_id": 1, "offer": 1, "user": user.id}) @@ -67,7 +67,7 @@ def test_error_create_favourite_job_offer_already_saved(user, job_offer): @pytest.mark.django_db def test_success_delete_favourite_job_offer_for_specified_user(user, job_offer): - view = FavouriteAPIView.as_view() + view = FavouriteDeleteAPIView.as_view() favourite = Favourite.objects.create(offer=job_offer, user=user) request = factory.delete(f'/api/favourite/{favourite.id}/') @@ -78,7 +78,7 @@ def test_success_delete_favourite_job_offer_for_specified_user(user, job_offer): @pytest.mark.django_db def test_error_delete_favourite_job_offer_for_not_authenticated_user(user, job_offer): - view = FavouriteAPIView.as_view() + view = FavouriteDeleteAPIView.as_view() favourite = Favourite.objects.create(offer=job_offer, user=user) request = factory.delete(f'/api/favourite/{favourite.id}/') diff --git a/utils/base_model.py b/utils/base_model.py new file mode 100644 index 0000000..bf618bd --- /dev/null +++ b/utils/base_model.py @@ -0,0 +1,11 @@ +from django.db import models + + +class BaseModel(models.Model): + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now=True) + + class Meta: + abstract = True + ordering = ["-created_at"] + get_latest_by = "created_at"