Skip to content

Commit

Permalink
Merge branch 'development' of https://github.com/breatheco-de/apiv2 i…
Browse files Browse the repository at this point in the history
…nto development
  • Loading branch information
jefer94 committed Jun 18, 2024
2 parents e18951d + 7f037b8 commit 3c2ee21
Show file tree
Hide file tree
Showing 24 changed files with 903 additions and 323 deletions.
17 changes: 16 additions & 1 deletion breathecode/authenticate/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
import os

from django.urls import path
from linked_services.rest_framework.views import app_webhook, authorize_view

Expand Down Expand Up @@ -67,6 +69,19 @@
sync_gitpod_users_view,
)

# avoiding issues on test environment due that the fixture are loaded after this app
ENV = os.getenv('ENV')
TEST_ENV = (ENV == 'test' or ENV not in ['development', 'staging', 'production'])
LOGIN_URL = '/v1/auth/view/login'
app_url = os.getenv('APP_URL')

if TEST_ENV and not app_url:
import faker

fake = faker.Faker()

app_url = fake.url().replace('http://', 'https://')

app_name = 'authenticate'
urlpatterns = [
path('confirmation/<str:token>', ConfirmEmailView.as_view(), name='confirmation_token'),
Expand Down Expand Up @@ -142,7 +157,7 @@

# authorize
path('authorize/<str:app_slug>',
authorize_view(login_url='/v1/auth/view/login', get_language=get_user_language),
authorize_view(login_url=LOGIN_URL, app_url=app_url, get_language=get_user_language),
name='authorize_slug'),

# apps
Expand Down
10 changes: 5 additions & 5 deletions breathecode/celery.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

# the rest of your Celery file contents go here
import os
from datetime import datetime, timedelta
from datetime import UTC, datetime
from typing import TypedDict

from celery import Celery
Expand Down Expand Up @@ -123,15 +123,15 @@ def __exit__(self, *args, **kwargs):
if len(data[i]) >= 2:
data[i].sort(key=lambda x: x['created_at'])

if datetime.utcnow() - data[i][-1]['created_at'] < delta:
if datetime.now(UTC) - data[i][-1]['created_at'] < delta:
available[i] = False
data[i] = data[i][-2:]
else:
available[i] = True
data[i] = data[i][-1:]

elif len(data[i]) == 1:
if datetime.utcnow() - data[i][0]['created_at'] < delta:
if datetime.now(UTC) - data[i][0]['created_at'] < delta:
available[i] = False
else:
available[i] = True
Expand All @@ -142,7 +142,7 @@ def __exit__(self, *args, **kwargs):
found = False
for i in range(workers):
if available[i]:
data[i].append({'pid': worker_id, 'created_at': datetime.utcnow()})
data[i].append({'pid': worker_id, 'created_at': datetime.now(UTC)})
found = True
break

Expand All @@ -153,7 +153,7 @@ def __exit__(self, *args, **kwargs):
if len(data[i]) < len(pointer):
pointer = data[i]

pointer.append({'pid': worker_id, 'created_at': datetime.utcnow()})
pointer.append({'pid': worker_id, 'created_at': datetime.now(UTC)})

cache.set('workers', data, timeout=None)
break
Expand Down
60 changes: 53 additions & 7 deletions breathecode/mentorship/actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,21 @@
from datetime import timedelta

import pytz
from asgiref.sync import sync_to_async
from dateutil.relativedelta import relativedelta
from django.db.models import Q, QuerySet
from django.shortcuts import render
from django.utils import timezone
from google.apps.meet_v2.types import Space, SpaceConfig

import breathecode.activity.tasks as tasks_activity
from breathecode.mentorship.exceptions import ExtendSessionException
from breathecode.services.daily.client import DailyClient
from breathecode.services.google_meet.google_meet import GoogleMeet
from breathecode.utils.datetime_integer import duration_to_str
from capyc.rest_framework.exceptions import ValidationException

from .models import MentorProfile, MentorshipBill, MentorshipSession
from .models import MentorProfile, MentorshipBill, MentorshipService, MentorshipSession

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -91,12 +94,20 @@ def get_pending_sessions_or_create(token, mentor, service, mentee=None):
is_online=True,
service=service,
ends_at=timezone.now() + duration)
daily = DailyClient()
room = daily.create_room(exp_in_seconds=service.duration.seconds)
session.online_meeting_url = room['url']
session.name = room['name']
session.mentee = mentee
session.save()

if session.service.video_provider == MentorshipService.VideoProvider.GOOGLE_MEET:
create_room_on_google_meet(session)

elif session.service.video_provider == MentorshipService.VideoProvider.DAILY:
daily = DailyClient()
room = daily.create_room(exp_in_seconds=service.duration.seconds)
session.online_meeting_url = room['url']
session.name = room['name']
session.mentee = mentee
session.save()

else:
raise Exception('Invalid video provider')

if mentee:
tasks_activity.add_activity.delay(mentee.id,
Expand Down Expand Up @@ -392,3 +403,38 @@ def mentor_is_ready(mentor: MentorProfile):
raise Exception(f'Mentor {mentor.name} online meeting URL is failing.')

return True


def create_room_on_google_meet(session: MentorshipSession) -> None:
"""Create a room on google meet for a mentorship session."""

if isinstance(session, MentorshipSession) is False:
raise Exception('session argument must be a MentorshipSession')

if session.service.video_provider != session.service.VideoProvider.GOOGLE_MEET:
raise Exception('Video provider must be Google Meet')

if not session.service:
raise Exception('Mentorship session doesn\'t have a service associated with it')

mentor = session.mentor

meet = GoogleMeet()
if session.id is None:
session.save()

title = (f'{session.service.name} {session.id} | '
f'{mentor.user.first_name} {mentor.user.last_name}')
s = Space(
name=title,
config=SpaceConfig(access_type=SpaceConfig.AccessType.OPEN),
)
space = meet.create_space(space=s)
session.online_meeting_url = space.meeting_uri
session.name = title
session.save()


@sync_to_async
def acreate_room_on_google_meet(session: MentorshipSession) -> None:
return create_room_on_google_meet(session)
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
# Generated by Django 5.0.6 on 2024-06-17 22:09

import breathecode.utils.validators.language
import datetime
import django.db.models.deletion
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('admissions', '0064_academy_legal_name'),
('mentorship', '0028_mentorshipsession_questions_and_answers'),
]

operations = [
migrations.AddField(
model_name='mentorshipservice',
name='video_provider',
field=models.CharField(blank=True,
choices=[('DAILY', 'Daily'), ('GOOGLE_MEET', 'Google Meet')],
default=None,
max_length=15),
),
migrations.AlterField(
model_name='mentorshipservice',
name='allow_mentee_to_extend',
field=models.BooleanField(blank=True,
default=None,
help_text='If true, mentees will be able to extend mentorship session'),
),
migrations.AlterField(
model_name='mentorshipservice',
name='allow_mentors_to_extend',
field=models.BooleanField(blank=True,
default=None,
help_text='If true, mentors will be able to extend mentorship session'),
),
migrations.AlterField(
model_name='mentorshipservice',
name='duration',
field=models.DurationField(blank=True,
default=None,
help_text='Default duration for mentorship sessions of this service'),
),
migrations.AlterField(
model_name='mentorshipservice',
name='language',
field=models.CharField(blank=True,
default=None,
help_text='ISO 639-1 language code + ISO 3166-1 alpha-2 country code, e.g. en-US',
max_length=5,
validators=[breathecode.utils.validators.language.validate_language_code]),
),
migrations.AlterField(
model_name='mentorshipservice',
name='max_duration',
field=models.DurationField(
blank=True,
default=None,
help_text='Maximum allowed duration or extra time, make it 0 for unlimited meetings'),
),
migrations.AlterField(
model_name='mentorshipservice',
name='missed_meeting_duration',
field=models.DurationField(
blank=True,
default=None,
help_text="Duration that will be paid when the mentee doesn't come to the session"),
),
migrations.CreateModel(
name='AcademyMentorshipSettings',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('duration',
models.DurationField(default=datetime.timedelta(seconds=3600),
help_text='Default duration for mentorship sessions of this service')),
('max_duration',
models.DurationField(
default=datetime.timedelta(seconds=7200),
help_text='Maximum allowed duration or extra time, make it 0 for unlimited meetings')),
('missed_meeting_duration',
models.DurationField(
default=datetime.timedelta(seconds=600),
help_text="Duration that will be paid when the mentee doesn't come to the session")),
('language',
models.CharField(default='en',
help_text='ISO 639-1 language code + ISO 3166-1 alpha-2 country code, e.g. en-US',
max_length=5,
validators=[breathecode.utils.validators.language.validate_language_code])),
('allow_mentee_to_extend',
models.BooleanField(default=True,
help_text='If true, mentees will be able to extend mentorship session')),
('allow_mentors_to_extend',
models.BooleanField(default=True,
help_text='If true, mentors will be able to extend mentorship session')),
('video_provider',
models.CharField(choices=[('DAILY', 'Daily'), ('GOOGLE_MEET', 'Google Meet')],
default='GOOGLE_MEET',
max_length=15)),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
('academy', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='admissions.academy')),
],
),
]
Loading

0 comments on commit 3c2ee21

Please sign in to comment.