File size: 9,188 Bytes
b7a7f32
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
import json
import os
from hashlib import sha256
from typing import Any, List

import aiofiles
from fastapi import (
    APIRouter,
    Depends,
    FastAPI,
    File,
    Form,
    HTTPException,
    UploadFile,
    WebSocket,
    WebSocketDisconnect,
)
from fastapi.encoders import jsonable_encoder
from fastapi.responses import FileResponse, HTMLResponse
from sqlalchemy.orm import Session
from starlette.status import HTTP_406_NOT_ACCEPTABLE

from core.config import settings
from core.security import get_uid_hash
from core.websocket import ws, ChatMessageTypes
from cruds import crud_class_session, crud_file, crud_user
from forms.class_session import ClassSessionCreateForm
from models import ClassSession as ClassSessionModel
from models import File as FileModel
from schemas.class_session import (
    ClassSession,
    ClassSessionCreate,
    ClassSessionReturn,
    ClassSessionUpdate,
    ClassSessionTeacherReturn,
    AttendanceUpdate,
    ParticipantOfClassSession,
)
from schemas.file import FileCreate
from schemas.group import GroupStudentReturn
from utils import deps
from utils.deps import get_current_active_teacher_or_above, get_current_active_user, get_current_active_ws_user
import datetime
import cruds

router = APIRouter()


@router.get("/", response_model=List[ClassSessionReturn])
def get_class_session(
    db: Session = Depends(deps.get_db),
    user=Depends(get_current_active_user),
    skip: int = 0,
    limit: int = 100,
) -> Any:
    class_sessions = crud_class_session.get_user_class_session(db, user=user)
    return class_sessions


@router.get("/active", response_model=List[ClassSessionReturn])
def get_active_class_session(
    db: Session = Depends(deps.get_db),
    user=Depends(get_current_active_user),
) -> Any:
    class_sessions = crud_class_session.get_user_class_session(db, user=user)
    active_class_sessions = []

    for class_session in class_sessions:
        if(class_session.start_time < datetime.datetime.now() and class_session.end_time > datetime.datetime.now()):
            active_class_sessions.append(class_session)

    return active_class_sessions


@router.post("/", response_model=ClassSession)
async def create_class_session(
    db: Session = Depends(deps.get_db),
    user=Depends(get_current_active_teacher_or_above),
    *,
    form: ClassSessionCreateForm = Depends(),
) -> Any:
    course_id = None
    for item in user.teacher_group:
        course_id = item.course.id if item.group.id == form.group else course_id

    if(course_id == None):
        raise HTTPException(
            status_code=HTTP_406_NOT_ACCEPTABLE, detail="Invalid group id!")

    data = ClassSessionCreate(
        start_time=form.start_time,
        end_time=form.end_time,
        instructor=[user.id]+(form.instructor or []),
        description=form.description,
        group_id=form.group,
        course_id=course_id,
    )

    class_session = crud_class_session.create(db, obj_in=data)

    hasher = sha256()
    hasher.update(bytes(f"{class_session.id}_{settings.SECRET_KEY}", "utf-8"))
    db_folder_path = os.path.join("class_files", hasher.hexdigest())
    folder_path = os.path.join(settings.UPLOAD_DIR_ROOT, db_folder_path)

    if not os.path.exists(folder_path):
        os.makedirs(folder_path)

    if form.file:
        for file in form.file:
            file_path = os.path.join(folder_path, file.filename)
            async with aiofiles.open(file_path, mode="wb") as f:
                content = await file.read()
                await f.write(content)

            db.add(
                FileModel(
                    name=file.filename,
                    path=db_folder_path,
                    file_type=file.content_type,
                    description=None,
                    class_session=class_session,
                )
            )
            db.commit()

    return class_session


@router.get("/{id}/", response_model=ClassSessionReturn)
def get_specific_class_session(
    db: Session = Depends(deps.get_db),
    user=Depends(get_current_active_user),
    *,
    id: int,
) -> Any:
    class_session = crud_class_session.get_user_class_session(
        db=db, user=user, id=id)
    return class_session


@router.get("/{id}/participants", response_model=List[ParticipantOfClassSession])
def get_specific_class_session(
    db: Session = Depends(deps.get_db),
    current_user=Depends(get_current_active_user),
    *,
    id: int,
) -> Any:
    class_session = crud_class_session.get(db, id)

    group = cruds.crud_group.get(db, class_session.group_id)

    participants = group.student + class_session.instructor

    return participants


@router.get("/{id}/attendance", response_model=ClassSessionTeacherReturn)
def get_class_session_with_attendance(
    db: Session = Depends(deps.get_db),
    user=Depends(get_current_active_teacher_or_above),
    *,
    id: int,
) -> Any:
    class_session = crud_class_session.get_user_class_session(
        db=db, user=user, id=id)
    return class_session


@router.put("/{id}/", response_model=ClassSession)
def update_class_session(
    db: Session = Depends(deps.get_db), *, id: int, obj_in: ClassSessionUpdate
) -> Any:
    class_session = crud_class_session.get(db, id)
    class_session = crud_class_session.update(
        db, db_obj=class_session, obj_in=obj_in)
    return class_session


@router.put("/{class_id}/files")
async def update_class_session(
    db: Session = Depends(deps.get_db),
    *,
    class_id: int,
    files: List[UploadFile] = File(None),
) -> Any:
    class_session = crud_class_session.get(db, class_id)

    hasher = sha256()
    hasher.update(bytes(f"{class_id}_{settings.SECRET_KEY}", "utf-8"))
    db_folder_path = os.path.join("class_files", hasher.hexdigest())
    folder_path = os.path.join(settings.UPLOAD_DIR_ROOT, db_folder_path)

    if not os.path.exists(folder_path):
        os.makedirs(folder_path)

    for file in files:
        file_path = os.path.join(folder_path, file.filename)
        async with aiofiles.open(file_path, mode="wb") as f:
            content = await file.read()
            await f.write(content)

        db.add(
            FileModel(
                name=file.filename,
                path=db_folder_path,
                file_type=file.content_type,
                description=None,
                class_session=class_session,
            )
        )
        db.commit()
    return {"msg": "success"}


@router.put("/{id}/attendance")
def attendance_of_class_session(
    db: Session = Depends(deps.get_db),
    *,
    id: int,
    obj_in: AttendanceUpdate,
    current_teacher=Depends(get_current_active_teacher_or_above),
) -> Any:
    class_session = crud_class_session.get_user_class_session(
        db=db, user=current_teacher, id=id
    )
    if not class_session:
        raise HTTPException(
            status_code=403, detail="Class session access denied!")
    class_session = crud_class_session.attendance_update(
        db, db_obj=class_session, obj_in=obj_in
    )
    return {"msg": "success"}


# @router.post("/{id}/file/")
# async def create_upload_files(
# db: Session = Depends(deps.get_db),
# files: List[UploadFile] = File(...),
# current_teacher=Depends(
# get_current_active_teacher_or_above
# ),  # FIXME : Get current user ?
# *,
# id: int,
# ):
# class_session = crud_class_session.get_user_class_session(
# db=db, user=current_teacher, id=id
# )

# if not class_session:
# raise HTTPException(status_code=403, detail="Error ID: 100")  # Access denied!

# FILE_PATH = os.path.join("static", settings.UPLOAD_DIR_ROOT)
# working_directory = os.getcwd()
# FILE_PATH = os.path.join(working_directory, FILE_PATH)

# for file in files:
# filename = f"{FILE_PATH}/{id}/{file.filename}"
# async with aiofiles.open(filename, mode="wb") as f:
# content = await file.read()
# await f.write(content)

# obj_in = ClassSessionUpdate(file=[file.filename for file in files])
# crud_class_session.update(db=db, db_obj=class_session, obj_in=obj_in)

# return {"msg": "success"}


@router.websocket("/ws/{id}/")
async def websocket_endpoint(
    db: Session = Depends(deps.get_db),
    *,
    websocket: WebSocket,
    req_user=Depends(get_current_active_ws_user),
    id: int,
):
    user_id = req_user.id
    class_session = crud_class_session.get_user_class_session(
        db=db, user=req_user, id=id
    )
    if not class_session:
        raise HTTPException(
            status_code=403, detail="Error Code: 144"
        )  # User doesn't have access to classsession
    await ws.connect(websocket=websocket, class_session_id=id, user_id=user_id)
    try:
        while True:
            data = await websocket.receive_json()
            if data.get("msg_type") == ChatMessageTypes.MESSAGE_HISTORY.value:
                await ws.send_history(websocket, id)
            else:
                await ws.message(
                    websocket=websocket,
                    user_id=user_id,
                    class_session_id=id,
                    message=data.get("message"),
                    anon=data.get("anon"),
                )
    except WebSocketDisconnect:
        await ws.disconnect(websocket, class_session_id=id, user_id=user_id)