Skip to content

Commit

Permalink
Merge branch 'main' of https://github.com/breatheco-de/apiv2
Browse files Browse the repository at this point in the history
  • Loading branch information
alesanchezr committed Nov 4, 2024
2 parents 112dea5 + cdaa714 commit 4b883ad
Show file tree
Hide file tree
Showing 71 changed files with 4,547 additions and 1,014 deletions.
1 change: 1 addition & 0 deletions .flags
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
BYPASS_CONSUMPTION=0
4 changes: 1 addition & 3 deletions .github/workflows/checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ on:
pull_request: {}

env:
PYTHON_VERSION: 3.12.3
PYTHON_VERSION: 3.12.7
PYTHONUNBUFFERED: 1
APP_URL: https://4geeks.com

Expand All @@ -20,7 +20,6 @@ env:
# |> naming-conventions |> linter
# |> unexpected-behaviors |> pages


jobs:
cache:
runs-on: ubuntu-latest
Expand Down Expand Up @@ -142,7 +141,6 @@ jobs:
id: calculate-md5-2
run: pipenv run pip freeze -r requirements2.txt > requirements2.txt


- name: Check Pipfile.lock is up-to-date
run: diff requirements.txt requirements2.txt

Expand Down
4 changes: 2 additions & 2 deletions .gitpod.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ RUN sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release
wget --quiet -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - && \
echo "deb https://apt.llvm.org/$(lsb_release -cs)/ llvm-toolchain-$(lsb_release -cs)-18 main" | sudo tee /etc/apt/sources.list.d/llvm.list && \
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add - && \
sudo install-packages postgresql-16 postgresql-contrib-16 redis-server
sudo install-packages postgresql-16 postgresql-contrib-16 redis-server netcat

# Setup PostgreSQL server for user gitpod
ENV PATH="/usr/lib/postgresql/16/bin:$PATH"
Expand All @@ -29,7 +29,7 @@ ENV PGHOSTADDR="127.0.0.1"
ENV PGDATABASE="postgres"
COPY --chown=gitpod:gitpod postgresql-hook.bash $HOME/.bashrc.d/200-postgresql-launch

# RUN pyenv install 3.12.3 && pyenv global 3.12.3
# RUN pyenv install 3.12.7 && pyenv global 3.12.7
# RUN pip install pipenv

USER gitpod
Expand Down
1,529 changes: 913 additions & 616 deletions Pipfile.lock

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions breathecode/activity/views.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import json

from capyc.core.i18n import translation
from capyc.rest_framework.exceptions import ValidationException
from django.contrib.auth.models import User
from django.db.models import Avg, Count, Q, Sum
from google.cloud import bigquery
Expand All @@ -14,8 +16,6 @@
from breathecode.authenticate.actions import get_user_language
from breathecode.services.google_cloud.big_query import BigQuery
from breathecode.utils import HeaderLimitOffsetPagination, capable_of, getLogger
from breathecode.utils.i18n import translation
from capyc.rest_framework.exceptions import ValidationException

from .utils import (
generate_created_at,
Expand Down
4 changes: 2 additions & 2 deletions breathecode/admissions/actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ def validate(_type, _log, day, index):


def is_no_saas_student_up_to_date_in_any_cohort(
user: User, cohort: Optional[Cohort] = None, academy: Optional[Cohort] = None
user: User, cohort: Optional[Cohort] = None, academy: Optional[Cohort] = None, default: bool = True
) -> str:
no_available_as_saas = Q(cohort__available_as_saas=False) | Q(
cohort__available_as_saas=None, cohort__academy__available_as_saas=False
Expand Down Expand Up @@ -337,4 +337,4 @@ def is_no_saas_student_up_to_date_in_any_cohort(
return False

# if no cohorts were found, we assume that the user is up to date
return True
return default
2 changes: 1 addition & 1 deletion breathecode/admissions/serializers.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import logging
from collections import OrderedDict

from capyc.rest_framework.exceptions import ValidationException
from django.contrib.auth.models import User
from django.db.models import Q

Expand All @@ -9,7 +10,6 @@
from breathecode.assignments.serializers import TaskGETSmallSerializer
from breathecode.authenticate.models import CredentialsGithub, ProfileAcademy
from breathecode.utils import localize_query, serializers, serpy
from capyc.rest_framework.exceptions import ValidationException

from .actions import haversine, test_syllabus
from .models import (
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
"""
Test mentorhips
"""

import capyc.pytest as capy
import pytest

from ...actions import is_no_saas_student_up_to_date_in_any_cohort


@pytest.fixture(autouse=True)
def setup(db: None):
yield


@pytest.mark.parametrize("default", [True, False])
def test_default(database: capy.Database, default: bool):
model = database.create(user=1)
res = is_no_saas_student_up_to_date_in_any_cohort(model.user, default=default)
assert res == default


class TestNoSaasStudent:

@pytest.mark.parametrize("educational_status", ["ACTIVE", "GRADUATED"])
@pytest.mark.parametrize("finantial_status", ["FULLY_PAID", "UP_TO_DATE"])
@pytest.mark.parametrize(
"extra",
[
{"cohort": {"available_as_saas": False}, "academy": {"available_as_saas": True}},
{"cohort": {"available_as_saas": None}, "academy": {"available_as_saas": False}},
],
)
def test_true(self, database: capy.Database, educational_status: str, finantial_status: str, extra: dict):
model = database.create(
user=1,
city=1,
country=1,
cohort_user={"educational_status": educational_status, "finantial_status": finantial_status},
**extra,
)
res = is_no_saas_student_up_to_date_in_any_cohort(model.user, default=False)
assert res == True

@pytest.mark.parametrize("educational_status", ["ACTIVE"])
@pytest.mark.parametrize("finantial_status", ["LATE"])
@pytest.mark.parametrize(
"extra",
[
{"cohort": {"available_as_saas": False}, "academy": {"available_as_saas": True}},
{"cohort": {"available_as_saas": None}, "academy": {"available_as_saas": False}},
],
)
def test_false(self, database: capy.Database, educational_status: str, finantial_status: str, extra: dict):
model = database.create(
user=1,
city=1,
country=1,
cohort_user={"educational_status": educational_status, "finantial_status": finantial_status},
**extra,
)
res = is_no_saas_student_up_to_date_in_any_cohort(model.user, default=True)
assert res == False


@pytest.mark.parametrize("default", [True, False])
def test_default(database: capy.Database, default: bool):
model = database.create(user=1)
res = is_no_saas_student_up_to_date_in_any_cohort(model.user, default=default)
assert res == default


class TestSaasStudent:

@pytest.mark.parametrize("educational_status", ["ACTIVE", "GRADUATED"])
@pytest.mark.parametrize("finantial_status", ["FULLY_PAID", "UP_TO_DATE"])
@pytest.mark.parametrize(
"extra",
[
{"cohort": {"available_as_saas": True}, "academy": {"available_as_saas": False}},
{"cohort": {"available_as_saas": None}, "academy": {"available_as_saas": True}},
],
)
def test_default_false(self, database: capy.Database, educational_status: str, finantial_status: str, extra: dict):
model = database.create(
user=1,
city=1,
country=1,
cohort_user={"educational_status": educational_status, "finantial_status": finantial_status},
**extra,
)
res = is_no_saas_student_up_to_date_in_any_cohort(model.user, default=False)
assert res == False

@pytest.mark.parametrize("educational_status", ["ACTIVE"])
@pytest.mark.parametrize("finantial_status", ["LATE"])
@pytest.mark.parametrize(
"extra",
[
{"cohort": {"available_as_saas": True}, "academy": {"available_as_saas": False}},
{"cohort": {"available_as_saas": None}, "academy": {"available_as_saas": True}},
],
)
def test_default_true(self, database: capy.Database, educational_status: str, finantial_status: str, extra: dict):
model = database.create(
user=1,
city=1,
country=1,
cohort_user={"educational_status": educational_status, "finantial_status": finantial_status},
**extra,
)
res = is_no_saas_student_up_to_date_in_any_cohort(model.user, default=True)
assert res == True
7 changes: 5 additions & 2 deletions breathecode/admissions/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import pytz
from adrf.decorators import api_view
from capyc.core.i18n import translation
from capyc.rest_framework.exceptions import ValidationException
from django.contrib.auth.models import AnonymousUser, User
from django.db.models import FloatField, Max, Q, Value
Expand Down Expand Up @@ -32,7 +33,6 @@
localize_query,
)
from breathecode.utils.find_by_full_name import query_like_by_full_name
from breathecode.utils.i18n import translation
from breathecode.utils.views import render_message

from .actions import find_asset_on_json, test_syllabus, update_asset_on_json
Expand Down Expand Up @@ -1834,6 +1834,9 @@ def get(self, request, syllabus_id, version, academy_id):
# Write the data rows for each day
for day in sorted(syllabus_version.json["days"], key=lambda x: x["position"]):
week_number = math.ceil(cumulative_days / class_days_per_week)
if "technologies" not in day:
day["technologies"] = []

if lang == "es":
writer.writerow(
[
Expand All @@ -1856,7 +1859,7 @@ def get(self, request, syllabus_id, version, academy_id):
day.get("teacher_instructions", ""),
]
)
cumulative_days += day["duration_in_days"]
cumulative_days += day["duration_in_days"] if "duration_in_days" in day else 1
return response


Expand Down
2 changes: 1 addition & 1 deletion breathecode/assessment/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ def change_status_answered(modeladmin, request, queryset):

@admin.register(UserAssessment)
class UserAssessmentAdmin(admin.ModelAdmin):
search_fields = ["title", "question__assessment__title"]
search_fields = ["title", "assessment__title"]
readonly_fields = ("token",)
list_display = ["id", "title", "current_status", "lang", "owner", "total_score", "assessment", "academy"]
list_filter = ["lang", "status", "academy"]
Expand Down
10 changes: 8 additions & 2 deletions breathecode/assessment/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -294,14 +294,20 @@ def __init__(self, *args, **kwargs):
self._old_status = self.status

def save(self, *args, **kwargs):

is_creating = self.pk is None
if not self.pk:
self.token = binascii.hexlify(os.urandom(20)).decode()

_instance = super().save(*args, **kwargs)

# Answer is being closed
if self.status != self._old_status:
if is_creating or self.status != self._old_status:
signals.userassessment_status_updated.send_robust(instance=self, sender=self.__class__)

return super().save(*args, **kwargs)
return _instance



def get_score(self):

Expand Down
13 changes: 11 additions & 2 deletions breathecode/assessment/serializers.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from capyc.core.i18n import translation
from capyc.rest_framework.exceptions import ValidationException
from django.contrib.auth.models import AnonymousUser
from django.utils import timezone
Expand All @@ -6,7 +7,6 @@
from breathecode.admissions.models import Academy
from breathecode.utils import serpy
from breathecode.utils.datetime_integer import duration_to_str, from_now
from breathecode.utils.i18n import translation

from .models import Answer, Assessment, Option, Question, UserAssessment

Expand Down Expand Up @@ -162,14 +162,23 @@ class HookUserAssessmentSerializer(serpy.Serializer):
status_text = serpy.Field()

conversion_info = serpy.Field()
total_score = serpy.Field()
comment = serpy.Field()

started_at = serpy.Field()
finished_at = serpy.Field()

created_at = serpy.Field()

summary = serpy.MethodField()
def get_summary(self, obj):
total_score, last_one = obj.get_score()

last_answer = None
if last_one is not None:
last_answer = AnswerSmallSerializer(last_one).data

return {"last_answer": last_answer, "live_score": total_score}


class PublicUserAssessmentSerializer(serpy.Serializer):
id = serpy.Field()
Expand Down
5 changes: 3 additions & 2 deletions breathecode/assessment/views.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
from datetime import datetime

from capyc.core.i18n import translation
from capyc.rest_framework.exceptions import ValidationException
from django.db.models import Q
from django.utils import timezone
from rest_framework import status
Expand All @@ -12,8 +15,6 @@
from breathecode.marketing.serializers import FormEntryBigSerializer, PostFormEntrySerializer
from breathecode.marketing.tasks import persist_single_lead
from breathecode.utils import APIViewExtensions, GenerateLookupsMixin, capable_of
from breathecode.utils.i18n import translation
from capyc.rest_framework.exceptions import ValidationException

from .models import Answer, Assessment, AssessmentLayout, AssessmentThreshold, Option, Question, UserAssessment
from .serializers import (
Expand Down
5 changes: 3 additions & 2 deletions breathecode/assignments/permissions/consumers.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import logging

from capyc.core.i18n import translation
from capyc.rest_framework.exceptions import PaymentException

from breathecode.admissions.actions import is_no_saas_student_up_to_date_in_any_cohort
from breathecode.authenticate.actions import get_user_language
from breathecode.payments.models import Service
from breathecode.utils.decorators import ServiceContext
from breathecode.utils.i18n import translation
from capyc.rest_framework.exceptions import PaymentException

logger = logging.getLogger(__name__)

Expand Down
2 changes: 1 addition & 1 deletion breathecode/assignments/receivers.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import logging
from typing import Any, Type

from capyc.core.i18n import translation
from django.dispatch import receiver

from breathecode.admissions.signals import syllabus_asset_slug_updated
from breathecode.assignments import tasks
from breathecode.authenticate.actions import get_user_settings
from breathecode.authenticate.models import CredentialsGithub
from breathecode.notify.actions import send_email_message
from breathecode.utils.i18n import translation

from .models import RepositoryDeletionOrder, Task
from .signals import assignment_status_updated, status_updated
Expand Down
2 changes: 1 addition & 1 deletion breathecode/assignments/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from adrf.views import APIView
from asgiref.sync import sync_to_async
from capyc.core.i18n import translation
from capyc.rest_framework.exceptions import ValidationException
from circuitbreaker import CircuitBreakerError
from django.contrib import messages
Expand All @@ -30,7 +31,6 @@
from breathecode.utils.api_view_extensions.api_view_extensions import APIViewExtensions
from breathecode.utils.decorators import consume, has_permission
from breathecode.utils.decorators.capable_of import acapable_of
from breathecode.utils.i18n import translation
from breathecode.utils.multi_status_response import MultiStatusResponse

from .actions import deliver_task, sync_cohort_tasks
Expand Down
4 changes: 2 additions & 2 deletions breathecode/authenticate/actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

from adrf.requests import AsyncRequest
from asgiref.sync import sync_to_async
from capyc.core.i18n import translation
from capyc.rest_framework.exceptions import ValidationException
from django.contrib.auth.models import User
from django.core.handlers.wsgi import WSGIRequest
from django.db.models import Q
Expand All @@ -17,8 +19,6 @@
import breathecode.notify.actions as notify_actions
from breathecode.admissions.models import Academy, CohortUser
from breathecode.services.github import Github
from breathecode.utils.i18n import translation
from capyc.rest_framework.exceptions import ValidationException

from .models import (
AcademyAuthSettings,
Expand Down
Loading

0 comments on commit 4b883ad

Please sign in to comment.