Skip to content

Commit

Permalink
Merge pull request breatheco-de#1432 from breatheco-de/development
Browse files Browse the repository at this point in the history
Development
  • Loading branch information
tommygonzaleza authored Jul 30, 2024
2 parents 9127294 + e25c13a commit 632cee7
Show file tree
Hide file tree
Showing 9 changed files with 388 additions and 4 deletions.
1 change: 1 addition & 0 deletions .github/workflows/checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ name: Check

on:
push: {}
pull_request: {}

env:
PYTHON_VERSION: 3.12.3
Expand Down
1 change: 1 addition & 0 deletions breathecode/authenticate/actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -730,6 +730,7 @@ def accept_invite(accepting_ids=None, user=None):
invite.user = user

invite.status = "ACCEPTED"
invite.process_status = "DONE"
invite.save()


Expand Down
11 changes: 11 additions & 0 deletions breathecode/notify/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from breathecode.admissions.models import Academy
from breathecode.utils import serpy
from capyc.rest_framework.exceptions import ValidationException
from breathecode.authenticate.serializers import GetSmallAcademySerializer

from .models import Hook

Expand Down Expand Up @@ -42,3 +43,13 @@ def validate(self, data):
data["user"] = self.context["request"].user

return super().validate(data)


class SlackTeamSerializer(serpy.Serializer):
id = serpy.Field()
slack_id = serpy.Field()
name = serpy.Field()
academy = GetSmallAcademySerializer(required=False)
created_at = serpy.Field()
sync_status = serpy.Field()
sync_message = serpy.Field()
113 changes: 113 additions & 0 deletions breathecode/notify/tests/urls/tests_slack_team.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
"""
Test /slack/team
"""

import json

import pytest
from django.urls.base import reverse_lazy
from linked_services.django.actions import reset_app_cache
from rest_framework import status
from rest_framework.test import APIClient

from breathecode.tests.mixins.breathecode_mixin.breathecode import Breathecode


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


def get_serializer(team, data={}):
return {
"id": team.id,
"slack_id": team.slack_id,
"name": team.name,
"academy": {
"id": team.academy.id,
"name": team.academy.name,
"slug": team.academy.slug,
},
"created_at": team.created_at,
"sync_message": team.sync_message,
"sync_status": team.sync_status,
**data,
}


# When: no auth
# Then: response 401
def test_no_auth(bc: Breathecode, client: APIClient):
url = reverse_lazy("notify:slack_team")
response = client.get(url)

json = response.json()
expected = {"detail": "Authentication credentials were not provided.", "status_code": 401}

assert json == expected
assert response.status_code == status.HTTP_401_UNAUTHORIZED
assert bc.database.list_of("notify.SlackTeam") == []


def test_no_teams(bc: Breathecode, client: APIClient):
model = bc.database.create(user=1)
client.force_authenticate(model.user)

url = reverse_lazy("notify:slack_team")
response = client.get(url)

json = response.json()
expected = []
assert json == expected
assert response.status_code == status.HTTP_200_OK
assert bc.database.list_of("notify.SlackTeam") == []


def test_with_teams(bc: Breathecode, client: APIClient):
model = bc.database.create(user=1, slack_team=1)
client.force_authenticate(model.user)

url = reverse_lazy("notify:slack_team")
response = client.get(url)

json = response.json()
expected = [
get_serializer(model.slack_team, data={"created_at": bc.datetime.to_iso_string(model.slack_team.created_at)})
]

assert json == expected
assert response.status_code == status.HTTP_200_OK
assert bc.database.list_of("notify.SlackTeam") == [bc.format.to_dict(model.slack_team)]


def test_with_teams_filtering(bc: Breathecode, client: APIClient):
model = bc.database.create(user=1, academy={"slug": "hogwartz"}, slack_team=1)
client.force_authenticate(model.user)

url = reverse_lazy("notify:slack_team") + "?academy=hogwartz"
response = client.get(url)

json = response.json()
expected = [
get_serializer(model.slack_team, data={"created_at": bc.datetime.to_iso_string(model.slack_team.created_at)})
]

assert json == expected
assert response.status_code == status.HTTP_200_OK
assert bc.database.list_of("notify.SlackTeam") == [bc.format.to_dict(model.slack_team)]


def test_with_teams_filtering_no_academy(bc: Breathecode, client: APIClient):
model = bc.database.create(user=1, academy={"slug": "hogwartz"}, slack_team=1)
client.force_authenticate(model.user)

url = reverse_lazy("notify:slack_team") + "?academy=adasdasd"
response = client.get(url)

json = response.json()
expected = []

assert json == expected
assert response.status_code == status.HTTP_200_OK
assert bc.database.list_of("notify.SlackTeam") == [bc.format.to_dict(model.slack_team)]
2 changes: 2 additions & 0 deletions breathecode/notify/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
preview_slack_template,
HooksView,
get_sample_data,
SlackTeamsView,
)

app_name = "notify"
Expand All @@ -20,4 +21,5 @@
path("hook/sample", get_sample_data),
path("hook/<int:hook_id>/sample", get_sample_data),
path("slack/command", slack_command, name="slack_command"),
path("slack/team", SlackTeamsView.as_view(), name="slack_team"),
]
26 changes: 24 additions & 2 deletions breathecode/notify/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
from capyc.rest_framework.exceptions import ValidationException

from .actions import get_template_content
from .models import Hook
from .serializers import HookSerializer
from .models import Hook, SlackTeam
from .serializers import HookSerializer, SlackTeamSerializer
from .tasks import async_slack_action, async_slack_command

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -194,3 +194,25 @@ def delete(self, request, hook_id=None):
item.delete()

return Response({"details": f"Unsubscribed from {total} hooks"}, status=status.HTTP_200_OK)


class SlackTeamsView(APIView, GenerateLookupsMixin):
"""
List all snippets, or create a new snippet.
"""

extensions = APIViewExtensions(sort="-created_at", paginate=True)

def get(self, request):
handler = self.extensions(request)

items = SlackTeam.objects.all()
academy = request.GET.get("academy", None)
if academy is not None:
academy = academy.split(",")
items = items.filter(academy__slug__in=academy)

items = handler.queryset(items)
serializer = SlackTeamSerializer(items, many=True)

return handler.response(serializer.data)
51 changes: 51 additions & 0 deletions breathecode/payments/actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -679,6 +679,57 @@ def filter_consumables(
return queryset


def filter_void_consumable_balance(request: WSGIRequest, items: QuerySet[Consumable]):
consumables = items.filter(service_item__service__type="VOID")

if ids := request.GET.get("service"):
try:
ids = [int(x) for x in ids.split(",")]
except Exception:
raise ValidationException("service param must be integer")

consumables = consumables.filter(service_item__service__id__in=ids)

if slugs := request.GET.get("service_slug"):
slugs = slugs.split(",")

consumables = consumables.filter(service_item__service__slug__in=slugs)

if not consumables:
return []

result = {}

for consumable in consumables:
service = consumable.service_item.service
if service.id not in result:
result[service.id] = {
"balance": {
"unit": 0,
},
"id": service.id,
"slug": service.slug,
"items": [],
}

if consumable.how_many <= 0:
result[service.id]["balance"]["unit"] = -1

elif result[service.id]["balance"]["unit"] != -1:
result[service.id]["balance"]["unit"] += consumable.how_many

result[service.id]["items"].append(
{
"id": consumable.id,
"how_many": consumable.how_many,
"unit_type": consumable.unit_type,
"valid_until": consumable.valid_until,
}
)

return result.values()


def get_balance_by_resource(queryset: QuerySet, key: str):
result = []

Expand Down
Loading

0 comments on commit 632cee7

Please sign in to comment.