Skip to content

Main


Fragment

Bases: EmbeddedDocument

Embedded document for video fragments.

Attributes:

Name Type Description
name str

Name of the fragment

start str

Start time of the fragment

end str

End time of the fragment

progress int

Progress of the fragment

Source code in apps/augmentator/src/flask-server/main.py
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
class Fragment(db.EmbeddedDocument):
    """
    Embedded document for video fragments.

    Attributes
    ----------
    name : str
        Name of the fragment
    start : str
        Start time of the fragment
    end : str
        End time of the fragment
    progress : int
        Progress of the fragment
    """
    name = db.StringField()
    start = db.StringField()
    end =  db.StringField()
    progress = db.IntField()

Graphs

Bases: Document

Document for graph data.

Attributes:

Name Type Description
video_id str

Identifier for the video

annotator_name str

Name of the annotator

annotator_id str

Identifier for the annotator

email str

Email of the annotator

graph dict

Graph data

conceptVocabulary dict

Concept vocabulary data

Source code in apps/augmentator/src/flask-server/main.py
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
class Graphs(db.Document):
    """
    Document for graph data.

    Attributes
    ----------
    video_id : str
        Identifier for the video
    annotator_name : str
        Name of the annotator
    annotator_id : str
        Identifier for the annotator
    email : str
        Email of the annotator
    graph : dict
        Graph data
    conceptVocabulary : dict
        Concept vocabulary data
    """
    video_id = db.StringField()
    annotator_name = db.StringField()
    annotator_id = db.StringField()
    email = db.StringField()
    graph = db.DynamicField()
    conceptVocabulary = db.DynamicField()

HistoryLog

Bases: EmbeddedDocument

Embedded document for history logs.

Attributes:

Name Type Description
date datetime

Date of the log entry

request str

Request content

Source code in apps/augmentator/src/flask-server/main.py
247
248
249
250
251
252
253
254
255
256
257
258
259
class HistoryLog(db.EmbeddedDocument):
    """
    Embedded document for history logs.

    Attributes
    ----------
    date : datetime
        Date of the log entry
    request : str
        Request content
    """
    date = db.DateTimeField()
    request = db.StringField()

Student

Bases: Document

Document for student data.

Attributes:

Name Type Description
name str

First name of the student

surname str

Last name of the student

email str

Email address of the student

password_hash str

Hashed password of the student

code_reset_password str

Code for resetting password

nb_try_code_reset_password int

Number of attempts for resetting password

code_delete_account str

Code for deleting account

nb_try_code_delete_account int

Number of attempts for deleting account

video_history_list list

List of VideoHistory embedded documents

Methods:

Name Description
hash_password

Hash the student's password

verify_password

Verify the student's password

hash_code_reset_password

Hash the code for resetting password

verify_code_reset_password

Verify the code for resetting password

hash_code_delete_account

Hash the code for deleting account

verify_code_delete_account

Verify the code for deleting account

generate_auth_token

Generate an authentication token

verify_auth_token

Verify an authentication token

get_sorted_history

Get sorted video history

Source code in apps/augmentator/src/flask-server/main.py
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
class Student(db.Document):
    """
    Document for student data.

    Attributes
    ----------
    name : str
        First name of the student
    surname : str
        Last name of the student
    email : str
        Email address of the student
    password_hash : str
        Hashed password of the student
    code_reset_password : str
        Code for resetting password
    nb_try_code_reset_password : int
        Number of attempts for resetting password
    code_delete_account : str
        Code for deleting account
    nb_try_code_delete_account : int
        Number of attempts for deleting account
    video_history_list : list
        List of VideoHistory embedded documents

    Methods
    -------
    hash_password(password)
        Hash the student's password
    verify_password(password)
        Verify the student's password
    hash_code_reset_password(code)
        Hash the code for resetting password
    verify_code_reset_password(code)
        Verify the code for resetting password
    hash_code_delete_account(code)
        Hash the code for deleting account
    verify_code_delete_account(code)
        Verify the code for deleting account
    generate_auth_token(expires_in)
        Generate an authentication token
    verify_auth_token(token)
        Verify an authentication token
    get_sorted_history(by)
        Get sorted video history
    """
    name = db.StringField()
    surname = db.StringField()
    email = db.StringField()
    password_hash = db.StringField()

    code_reset_password = db.StringField()
    nb_try_code_reset_password = db.IntField()

    code_delete_account = db.StringField()
    nb_try_code_delete_account = db.IntField()

    video_history_list:list = db.EmbeddedDocumentListField(VideoHistory)

    def hash_password(self, password):
        hashed_pwd = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt())
        self.password_hash = hashed_pwd.decode('utf8')
        self.save()

    def verify_password(self, password):
        return bcrypt.checkpw(password.encode('utf-8'), self.password_hash.encode('utf-8'))



    def hash_code_reset_password(self, code):
        hashed_code = bcrypt.hashpw(code.encode('utf-8'), bcrypt.gensalt())
        self.code_reset_password = hashed_code.decode('utf8')
        self.save()

    def verify_code_reset_password(self, code):
        nb_try_code_reset_password_to_increment = self.nb_try_code_reset_password
        if nb_try_code_reset_password_to_increment is None:
            nb_try_code_reset_password_to_increment=0
        self.nb_try_code_reset_password = nb_try_code_reset_password_to_increment+ 1
        self.save()
        return bcrypt.checkpw(code.encode('utf-8'), self.code_reset_password.encode('utf-8'))



    def hash_code_delete_account(self, code):
        hashed_code = bcrypt.hashpw(code.encode('utf-8'), bcrypt.gensalt())
        self.code_delete_account = hashed_code.decode('utf8')
        self.save()

    def verify_code_delete_account(self, code):
        nb_try_code_delete_account_to_increment = self.nb_try_code_delete_account
        if nb_try_code_delete_account_to_increment is None:
            nb_try_code_delete_account_to_increment=0
        self.nb_try_code_delete_account = nb_try_code_delete_account_to_increment + 1
        self.save()
        return bcrypt.checkpw(code.encode('utf-8'), self.code_delete_account.encode('utf-8'))



    def generate_auth_token(self, expires_in=600):
        #return jwt.encode(
        #    {'email': self.email, 'exp': time.time() + expires_in},
        #    app.config['SECRET_KEY'], algorithm='HS256')
        return jwt.encode(
            {'email': self.email},
            app.config['SECRET_KEY'], algorithm='HS256')


    @staticmethod
    def verify_auth_token(token):
        try:
            data = jwt.decode(token, app.config['SECRET_KEY'],
                              algorithms=['HS256'])
        except:
            return
        return Student.objects(email=data['email']).first()


    def get_sorted_history(self,by:str):
        docs = self.video_history_list.copy()

        if by == "title":
            comp_funct = lambda video: get_video_title_from_url(video.video_url.split("watch?v=")[1])
        elif by == "lastChange":
            comp_funct = lambda video: video.lastChangesDate

        n = len(docs)
        # optimize code, so if the array is already sorted, it doesn't need
        # to go through the entire process
        # Traverse through all array elements
        for i in range(n):

            # range(n) also work but outer loop will
            # repeat one time more than needed.
            # Last i elements are already in place
            swapped = False
            for j in range(0, n-i-1):

                # traverse the array from 0 to n-i-1
                # Swap if the element found is greater
                # than the next element
                if comp_funct(docs[j]) > comp_funct(docs[j + 1]):
                    swapped = True
                    docs[j], docs[j + 1] = docs[j + 1], docs[j]

            if not swapped:
                # if we haven't needed to make a single swap, we
                # can just exit the main loop.
                return docs[::-1] if by == "lastChange" else docs

UnverifiedStudent

Bases: Document

Document for unverified student data.

Attributes:

Name Type Description
name str

First name of the student

surname str

Last name of the student

email str

Email address of the student

password_hash str

Hashed password of the student

code_on_creation_hash str

Code for account creation

nb_try_code_on_creation int

Number of attempts for account creation

Methods:

Name Description
hash_password

Hash the student's password

hash_code_on_creation

Hash the code for account creation

verify_code_on_creation

Verify the code for account creation

Source code in apps/augmentator/src/flask-server/main.py
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
class UnverifiedStudent(db.Document):
    """
    Document for unverified student data.

    Attributes
    ----------
    name : str
        First name of the student
    surname : str
        Last name of the student
    email : str
        Email address of the student
    password_hash : str
        Hashed password of the student
    code_on_creation_hash : str
        Code for account creation
    nb_try_code_on_creation : int
        Number of attempts for account creation

    Methods
    -------
    hash_password(password)
        Hash the student's password
    hash_code_on_creation(code)
        Hash the code for account creation
    verify_code_on_creation(code)
        Verify the code for account creation
    """
    name = db.StringField()
    surname = db.StringField()
    email = db.StringField()
    password_hash = db.StringField()

    code_on_creation_hash = db.StringField()
    nb_try_code_on_creation = db.IntField()


    def hash_password(self, password):
        hashed_pwd = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt())
        self.password_hash = hashed_pwd.decode('utf8')
        self.save()

    def hash_code_on_creation(self, code):
        hashed_code = bcrypt.hashpw(code.encode('utf-8'), bcrypt.gensalt())
        self.code_on_creation_hash = hashed_code.decode('utf8')
        self.save()

    def verify_code_on_creation(self, code):
        nb_try_code_on_creation_to_increment = self.nb_try_code_on_creation
        if nb_try_code_on_creation_to_increment is None:
            nb_try_code_on_creation_to_increment=0
        self.nb_try_code_on_creation = nb_try_code_on_creation_to_increment+ 1
        self.save()
        return bcrypt.checkpw(code.encode('utf-8'), self.code_on_creation_hash.encode('utf-8'))

VTStitles

Bases: EmbeddedDocument

Embedded document for video text segmentation titles.

Attributes:

Name Type Description
start_end_seconds list

List of start and end times in seconds

text str

Text content of the title

xywh_normalized list

List of normalized bounding box coordinates

Source code in apps/augmentator/src/flask-server/main.py
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
class VTStitles(db.EmbeddedDocument):
    """
    Embedded document for video text segmentation titles.

    Attributes
    ----------
    start_end_seconds : list
        List of start and end times in seconds
    text : str
        Text content of the title
    xywh_normalized : list
        List of normalized bounding box coordinates
    """
    start_end_seconds = db.ListField(db.DecimalField())
    text = db.StringField()
    xywh_normalized = db.ListField(db.DecimalField())

VideoHistory

Bases: EmbeddedDocument

Embedded document for video history.

Attributes:

Name Type Description
video_url str

URL of the video

video_watchtime int

Watch time of the video

fragment_clicks int

Number of fragment clicks

node_clicks int

Number of node clicks

transcript_clicks int

Number of transcript clicks

searchbar_clicks int

Number of search bar clicks

notes str

Notes for the video

lastChangesDate datetime

Date of the last changes

fragments_progress list

List of Fragment embedded documents

logs list

List of HistoryLog embedded documents

Source code in apps/augmentator/src/flask-server/main.py
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
class VideoHistory(db.EmbeddedDocument):
    """
    Embedded document for video history.

    Attributes
    ----------
    video_url : str
        URL of the video
    video_watchtime : int
        Watch time of the video
    fragment_clicks : int
        Number of fragment clicks
    node_clicks : int
        Number of node clicks
    transcript_clicks : int
        Number of transcript clicks
    searchbar_clicks : int
        Number of search bar clicks
    notes : str
        Notes for the video
    lastChangesDate : datetime
        Date of the last changes
    fragments_progress : list
        List of Fragment embedded documents
    logs : list
        List of HistoryLog embedded documents
    """
    video_url = db.StringField()
    video_watchtime = db.IntField()
    fragment_clicks = db.IntField()
    node_clicks = db.IntField()
    transcript_clicks = db.IntField()
    searchbar_clicks = db.IntField()
    notes = db.StringField()
    lastChangesDate = db.DateTimeField()
    fragments_progress = db.EmbeddedDocumentListField(Fragment)
    logs = db.EmbeddedDocumentListField(HistoryLog)

VideoStatistics

Bases: Document

Document for video statistics.

Attributes:

Name Type Description
video_url str

URL of the video

amountViewers int

Number of viewers

total_fragment_clicks int

Total number of fragment clicks

total_node_clicks int

Total number of node clicks

total_transcript_clicks int

Total number of transcript clicks

total_searchbar_clicks int

Total number of search bar clicks

viewersList list

List of viewer emails

Source code in apps/augmentator/src/flask-server/main.py
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
class VideoStatistics(db.Document):
    """
    Document for video statistics.

    Attributes
    ----------
    video_url : str
        URL of the video
    amountViewers : int
        Number of viewers
    total_fragment_clicks : int
        Total number of fragment clicks
    total_node_clicks : int
        Total number of node clicks
    total_transcript_clicks : int
        Total number of transcript clicks
    total_searchbar_clicks : int
        Total number of search bar clicks
    viewersList : list
        List of viewer emails
    """
    video_url = db.StringField()
    amountViewers = db.IntField()
    total_fragment_clicks = db.IntField()
    total_node_clicks = db.IntField()
    total_transcript_clicks = db.IntField()
    total_searchbar_clicks = db.IntField()
    viewersList = db.ListField(db.StringField())

VideoTextSegmentation

Bases: Document

Document for video text segmentation data.

Attributes:

Name Type Description
video_id str

Identifier for the video

slides_percentage float

Percentage of slides in the video

slide_titles list

List of VTStitles embedded documents

slide_startends list

List of start and end times for slides

slidish_frames_startend list

List of start and end frames for slides

Source code in apps/augmentator/src/flask-server/main.py
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
class VideoTextSegmentation(db.Document):
    """
    Document for video text segmentation data.

    Attributes
    ----------
    video_id : str
        Identifier for the video
    slides_percentage : float
        Percentage of slides in the video
    slide_titles : list
        List of VTStitles embedded documents
    slide_startends : list
        List of start and end times for slides
    slidish_frames_startend : list
        List of start and end frames for slides
    """
    video_id = db.StringField()
    slides_percentage = db.DecimalField()
    slide_titles = db.EmbeddedDocumentListField(VTStitles)
    slide_startends = db.ListField(db.ListField(db.DecimalField()))
    slidish_frames_startend = db.ListField(db.ListField(db.IntField()))

Videos

Bases: Document

Document for video metadata.

Attributes:

Name Type Description
video_id str

Identifier for the video

title str

Title of the video

creator str

Creator of the video

duration str

Duration of the video

segment_starts list

List of segment start times

segment_ends list

List of segment end times

extracted_keywords list

List of extracted keywords

language str

Language of the video

Source code in apps/augmentator/src/flask-server/main.py
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
class Videos(db.Document):
    """
    Document for video metadata.

    Attributes
    ----------
    video_id : str
        Identifier for the video
    title : str
        Title of the video
    creator : str
        Creator of the video
    duration : str
        Duration of the video
    segment_starts : list
        List of segment start times
    segment_ends : list
        List of segment end times
    extracted_keywords : list
        List of extracted keywords
    language : str
        Language of the video
    """
    video_id = db.StringField()
    title = db.StringField()
    creator = db.StringField()
    duration = db.StringField()
    segment_starts = db.ListField(db.StringField())
    segment_ends = db.ListField(db.StringField())
    extracted_keywords = db.ListField(db.StringField())
    language = db.StringField()

ConceptVideoData(video_id_list, concept_searched)

Get concept video data for a list of videos.

Parameters:

Name Type Description Default
video_id_list str

Comma-separated list of video IDs

required
concept_searched str

Concept to search for

required

Returns:

Type Description
str

JSON string containing concept video data

Source code in apps/augmentator/src/flask-server/main.py
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
@app.route('/api/ConceptVideoData/<video_id_list>/<concept_searched>')
@auth.login_required
def ConceptVideoData(video_id_list, concept_searched):
    """
    Get concept video data for a list of videos.

    Parameters
    ----------
    video_id_list : str
        Comma-separated list of video IDs
    concept_searched : str
        Concept to search for

    Returns
    -------
    str
        JSON string containing concept video data
    """
    #pymongo db config for query sparql
    client = pymongo.MongoClient(
            "mongodb+srv://"+MONGO_CLUSTER_USERNAME+":"+MONGO_CLUSTER_PASSWORD+"@clusteredurell.z8aeh.mongodb.net/edurell?retryWrites=true&w=majority")
    dbsparql = client.ekeel
    # retrieve from mongodb collection=graphs the all elements with the value of video_id
    collection = dbsparql.graphs

    videoList = video_id_list.split(',')
    result_list=[]
    for i in range(0,len(videoList)):
        video_id = videoList[i]
        # initialize the dicitonary where we save our results
        result = {
            'video_id':video_id,
            'concept_starttime':[],
            'concept_endtime':[],
            'explain':[],
            'list_preconcept': [],
            'list_prenotes':[],
            'list_postnotes':[],
            'list_derivatedconcept':[],
            'derivatedconcept_starttime':[],
            'derivatedconcept_endtime':[]

        }

        #print("?????????????????????????????START??????????????????????????????????")
        #print("start query: ",video_id," ",concept_searched)
        #print("result: ",result)

        # two options:
        ## 1. search newest annotation
        ### 2. combine every annotation of a video into a unique graph and make the query of that
        cursor = collection.find({"video_id":video_id})
        optiongraph = 2
        gr=Graph()


        if optiongraph == 1:
            ## 1. search newest annotation
            ## search for the newest in term of timestamp and get the idx of the newest document
            ## maybe it's pointless if the lastest is always the newest
            ## but in case the order changes in the future, this piece of code will make the ode work right regardless
            lastest = "1970-01-01T00:00:00.000000Z"
            lastest_idx = 0
            for idx,document in enumerate(cursor):
                if document is None:
                    continue
                gr=Graph().parse(data=json.dumps(document["graph"]), format='json-ld')
                qr = """
                        PREFIX oa: <http://www.w3.org/ns/oa#>
                        PREFIX edu: <https://teldh.github.io/edurell#>
                        PREFIX dctypes: <http://purl.org/dc/dcmitype/>
                        PREFIX dcterms: <http://purl.org/dc/terms/>

                        SELECT DISTINCT ?timestamp
                        WHERE {
                                ?who dcterms:created ?timestamp
                            }

                    """
                qres = gr.query(qr)
                #print("query result: ",qres)
                for row in qres:
                #   print("current_timestamp: ",lastest," / selected_timestamp: ",row['timestamp'])
                    if row['timestamp'] > lastest:
                        lastest = row['timestamp']
                        lastest_idx = idx
            #print("lastest_timestamp: ",lastest," lastest_idx: ",lastest_idx)
            #print("TESTTTTTTTTT       ",cursor)


            # select the newest document
            document = collection.find({"video_id":video_id})[lastest_idx]


            # Query the concept timeline and duration
            gr.parse(data=json.dumps(document["graph"]), format='json-ld')

            # initialize conceptVocabulary for the query
            gr.parse(data=json.dumps(document["conceptVocabulary"]), format='json-ld')

        else:
            ### 2. combine all annotation of a video together
            ### in mongodb we collect all annotation of a single video
            ### made by different people or the same
            ### this mode combine from the oldest to the newest into a single graph

            #print("start cursor for: ",video_id)
            for idx,document in enumerate(cursor):
            #   print("document ",video_id," idx: ",idx," \n\nGRAPH: ",document["graph"]," \n\nCONCEPT:  ",document["conceptVocabulary"]," \n\n")
            #  print("\n")
                # Query the concept timeline and duration
                if document["graph"]=="":
            #     print("\nIGNORE GRAPH: ")
                    continue
                if document["conceptVocabulary"] == "":
                #    print("\nIGNORE CONCEPT: ")

                    continue
                gr.parse(data=json.dumps(document["graph"]), format='json-ld')

                # initialize conceptVocabulary for the query

                gr.parse(data=json.dumps(document["conceptVocabulary"]), format='json-ld')




        ## --------------------------------------------------------------------------------------------------------------------------------------
        ## ---------------------------------------------------------QUERYCREATED-----------------------------------------------------------------
        ## --------------------------------------------------------------------------------------------------------------------------------------
        qr = """
                    PREFIX oa: <http://www.w3.org/ns/oa#>
                    PREFIX edu: <https://teldh.github.io/edurell#>
                    PREFIX dctypes: <http://purl.org/dc/dcmitype/>
                    PREFIX dcterms: <http://purl.org/dc/terms/>
                    PREFIX skos: <http://www.w3.org/2004/02/skos/core#>

                    SELECT DISTINCT ?created
                    WHERE{
                            ?who oa:motivatedBy oa:describing.
                            ?who dcterms:created ?created.
                            ?who a oa:Annotation.
                            ?who oa:hasBody ?c_id.
                            ?c_id skos:prefLabel ?c_selected.
                    }
        """


        qres = gr.query(qr, initBindings = {"c_selected":Literal(concept_searched, lang="en")})
        #print("query created")
        #print("qres: ",len(qres))
        for row in qres:
        #   print("_________________________________________")
        #  print(row['created'])
            result['created']=row['created']

        #print(result)



        ## --------------------------------------------------------------------------------------------------------------------------------------
        ## ---------------------------------------------------QUERYCONCEPTTIMELINE&SKOSNOTE------------------------------------------------------
        ## --------------------------------------------------------------------------------------------------------------------------------------
        qr = """
                    PREFIX oa: <http://www.w3.org/ns/oa#>
                    PREFIX edu: <https://teldh.github.io/edurell#>
                    PREFIX dctypes: <http://purl.org/dc/dcmitype/>
                    PREFIX dcterms: <http://purl.org/dc/terms/>
                    PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
                    SELECT ?concept_starttime ?concept_endtime ?explain
                    WHERE {

                            ?who oa:hasBody ?c_id.
                            ?c_id skos:prefLabel ?c_selected.
                            ?who oa:motivatedBy oa:describing.
                            ?who oa:hasTarget ?target.
                            ?target oa:hasSelector ?selector.
                            ?selector oa:hasStartSelector ?startselector.
                            ?startselector rdf:value ?concept_starttime.
                            ?selector oa:hasEndSelector ?endselector.
                            ?endselector rdf:value ?concept_endtime.
                            ?who skos:note ?explain               
                        }


                """

        qres = gr.query(qr, initBindings = {"c_selected":Literal(concept_searched, lang="en")})

        #print("qres: ",len(qres))
        for row in qres:
            #print("result: ",row['concept_starttime']," ",row['concept_endtime'])
        #   print("_________________________________________")
        #  print(row['concept_starttime'],"\n",row['concept_endtime'])

            result['concept_starttime'].append(row['concept_starttime'])
            result['concept_endtime'].append(row['concept_endtime'])
            result['explain'].append(row['explain'])


        ## --------------------------------------------------------------------------------------------------------------------------------------
        ## ---------------------------------------------------------QUERYPRECONCEPTS-------------------------------------------------------------
        ## --------------------------------------------------------------------------------------------------------------------------------------
        ## preconcepts that aren't explained: no conceptDefinition nor conceptExpansion

        qr = """
                    PREFIX oa: <http://www.w3.org/ns/oa#>
                    PREFIX edu: <https://teldh.github.io/edurell#>
                    PREFIX dctypes: <http://purl.org/dc/dcmitype/>
                    PREFIX dcterms: <http://purl.org/dc/terms/>
                    PREFIX skos: <http://www.w3.org/2004/02/skos/core#>

                    SELECT DISTINCT ?preconcept ?prenote
                    WHERE{
                            ?who oa:hasBody ?preconceptIRI.
                            ?c_id skos:prefLabel ?c_selected.
                            ?who oa:motivatedBy edu:linkingPrerequisite.
                            ?who oa:hasTarget ?target.
                            ?target dcterms:subject ?c_id.
                            ?preconceptIRI skos:prefLabel ?preconcept.
                            ?who skos:note ?prenote.

                    }


        """


        qres = gr.query(qr, initBindings = {"c_selected":Literal(concept_searched, lang="en")})
        #print("preconcept")
        #print("qres: ",len(qres))
        for row in qres:
        #   print("a_________________________________________")
        #  print(row['preconcept'])
            result['list_preconcept'].append(row['preconcept'])
            result['list_prenotes'].append(row['prenote'])

        #print(result)


        ## --------------------------------------------------------------------------------------------------------------------------------------
        ## ---------------------------------------------------------QUERYCONCEPTDERIVATED--------------------------------------------------------
        ## --------------------------------------------------------------------------------------------------------------------------------------
        qr = """
                    PREFIX oa: <http://www.w3.org/ns/oa#>
                    PREFIX edu: <https://teldh.github.io/edurell#>
                    PREFIX dctypes: <http://purl.org/dc/dcmitype/>
                    PREFIX dcterms: <http://purl.org/dc/terms/>
                    PREFIX skos: <http://www.w3.org/2004/02/skos/core#>

                    SELECT DISTINCT ?c_derivated ?postnote
                    WHERE{
                            ?who oa:hasBody ?c_id.
                            ?c_id skos:prefLabel ?c_selected.
                            ?who oa:motivatedBy edu:linkingPrerequisite.
                            ?who oa:hasTarget ?target.
                            ?target dcterms:subject ?c_derivatedIRI.
                            ?c_derivatedIRI skos:prefLabel ?c_derivated.
                            ?who skos:note ?postnote
                    }


        """
        """
            'list_derivatedconcept':[],
            'derivatedconcept_starttime':[],
            'derivatedconcept_endtime':[]
        """
        qres = gr.query(qr, initBindings = {"c_selected":Literal(concept_searched, lang="en")})
        #print("c_derivated")
        #print("qres: ",len(qres))
        for row in qres:
        #   print("b_________________________________________")
        #  print(row['c_derivated'])

            result['list_derivatedconcept'].append(row['c_derivated'])
            result['list_postnotes'].append(row['postnote'])






        for dc in result['list_derivatedconcept']:
            qr = """
                    PREFIX oa: <http://www.w3.org/ns/oa#>
                    PREFIX edu: <https://teldh.github.io/edurell#>
                    PREFIX dctypes: <http://purl.org/dc/dcmitype/>
                    PREFIX dcterms: <http://purl.org/dc/terms/>
                    PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
                    SELECT ?dc_starttime ?dc_endtime
                    WHERE {

                            ?who oa:hasBody ?c_id.
                            ?c_id skos:prefLabel ?c_selected.
                            ?who oa:motivatedBy oa:describing.
                            ?who oa:hasTarget ?target.
                            ?target oa:hasSelector ?selector.
                            ?selector oa:hasStartSelector ?startselector.
                            ?startselector rdf:value ?dc_starttime.
                            ?selector oa:hasEndSelector ?endselector.
                            ?endselector rdf:value ?dc_endtime.               
                        }


                """

            qres = gr.query(qr, initBindings = {"c_selected":Literal(dc, lang="en")})
            #print("qres: ",len(qres))
            for row in qres:
                #print("result: ",row['concept_starttime']," ",row['concept_endtime'])
            #   print("_________________________________________")
            #  print(row['dc_starttime'],"\n",row['dc_endtime'])
                result['derivatedconcept_starttime'].append(row['dc_starttime'])
                result['derivatedconcept_endtime'].append(row['dc_endtime'])



        ## --------------------------------------------------------------------------------------------------------------------------------------
        ## ---------------------------------------------------------SLIDISHNESS------------------------------------------------------------------
        ## --------------------------------------------------------------------------------------------------------------------------------------
        VTS=VideoTextSegmentation.objects(video_id = video_id)
        for VTSdoc in VTS:
        # print(VTSdoc.video_id)
        # print(VTSdoc.slides_percentage)
            result['slides_percentage'] = str(VTSdoc.slides_percentage)
        result_list.append(result)


    return json.dumps(result_list)

GetVideoTypeAndPrerequisite()

Get video type and prerequisite information.

Returns:

Type Description
dict

Dictionary containing video type and prerequisite information

Source code in apps/augmentator/src/flask-server/main.py
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
@app.route('/api/GetVideoTypeAndPrerequisite')
@auth.login_required
def GetVideoTypeAndPrerequisite():
    """
    Get video type and prerequisite information.

    Returns
    -------
    dict
        Dictionary containing video type and prerequisite information
    """
    client = pymongo.MongoClient(
        "mongodb+srv://"+MONGO_CLUSTER_USERNAME+":"+MONGO_CLUSTER_PASSWORD+"@clusteredurell.z8aeh.mongodb.net/edurell?retryWrites=true&w=majority")

    # retrieve from mongodb collection=graphs the all elements with the value of video_id
    db = client.ekeel
    collection = db.graphs

    videos = Videos.objects()
    result={}
    for v in videos:
        cursor = collection.find({"video_id":v.video_id})



        for document in cursor:
            #print("per ogni document in cursor: ",document["_id"]," ",document["conceptVocabulary"])
            #print("\n asd \n")
            if document["conceptVocabulary"] == "":
                print("NONE")
                continue

            gr=Graph()
            print("Generato grafo: ")
            # Query the concept timeline and duration
            gr.parse(data=json.dumps(document["graph"]), format='json-ld')

            # initialize conceptVocabulary for the query
            gr.parse(data=json.dumps(document["conceptVocabulary"]), format='json-ld')


        qr="""
                PREFIX oa: <http://www.w3.org/ns/oa#>
                PREFIX edu: <https://teldh.github.io/edurell#>
                PREFIX dctypes: <http://purl.org/dc/dcmitype/>
                PREFIX dcterms: <http://purl.org/dc/terms/>
                PREFIX skos: <http://www.w3.org/2004/02/skos/core#>

                SELECT DISTINCT ?video_id ?prerequisite ?typedef
                WHERE{
                    ?id_descr oa:motivatedBy oa:describing.
                    ?id_descr oa:hasTarget ?target_descr.
                    ?target_descr oa:hasSource ?video_id.
                    ?id_descr skos:note  ?typedef.

                    ?id_pre oa:motivatedBy edu:linkingPrerequisite.
                    ?id_pre oa:hasTarget ?target_link.
                    ?target_link oa:hasSource ?video_id.
                    ?id_pre oa:hasBody ?prerequisiteIRI.
                    ?prerequisiteIRI skos:prefLabel ?prerequisite.


                }

        """
        print("applico la query")
        qres = gr.query(qr)
        print("qres: ",len(qres)," ",qr)
        for row in qres:
            #print("_________________________________________")
            #print(row['video_id']," ",row['prerequisite']," ",row['typedef'])
            if v.video_id in result:
                if "prerequisite" in result[v.video_id]:
                    result[v.video_id]["prerequisite"].append(row['prerequisite'])
                else:
                    result[v.video_id]["prerequisite"] = []
                    result[v.video_id]["prerequisite"].append(row['prerequisite'])

                if "typedef" in result[v.video_id]:
                    result[v.video_id]["typedef"].append(row['typedef'])
                else:
                    result[v.video_id]["typedef"] = []
                    result[v.video_id]["typedef"].append(row['typedef'])
            else:
                result[v.video_id] = {}
                if "prerequisite" in result[v.video_id]:
                    result[v.video_id]["prerequisite"].append(row['prerequisite'])
                else:
                    result[v.video_id]["prerequisite"] = []
                    result[v.video_id]["prerequisite"].append(row['prerequisite'])

                if "typedef" in result[v.video_id]:
                    result[v.video_id]["typedef"].append(row['typedef'])
                else:
                    result[v.video_id]["typedef"] = []
                    result[v.video_id]["typedef"].append(row['typedef'])

        VTS=VideoTextSegmentation.objects(video_id = v.video_id)
        for VTSdoc in VTS:
            print(VTSdoc.video_id)
            print(VTSdoc.slides_percentage)
            if v.video_id in result:
                result[v.video_id]['slides_percentage'] = VTSdoc.slides_percentage
            else:
                result[v.video_id] = {}
                result[v.video_id]['slides_percentage'] = VTSdoc.slides_percentage
    return result

add_history()

Update user history for a specific video.

Returns:

Type Description
Response

JSON response with the student's email

Source code in apps/augmentator/src/flask-server/main.py
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
@app.route('/api/update_user_history',  methods=['POST'])
@auth.login_required
def add_history():
    """
    Update user history for a specific video.

    Returns
    -------
    flask.Response
        JSON response with the student's email
    """
    student= g.student
    #get data from request
    video_url_input = request.json.get('url')
    video_watchtime_input = request.json.get('video_watchtime')
    fragment_clicks_input = request.json.get('fragment_clicks')
    node_clicks_input = request.json.get('node_clicks')
    transcript_clicks_input = request.json.get('transcript_clicks')
    searchbar_clicks_input = request.json.get('searchbar_clicks')
    notes_input = request.json.get('notes')
    fragments_input = request.json.get('fragments')

    if video_url_input is None:
        abort(400, "The video url is missing")    # missing arguments

    #set None numbers to zero to avoid errors in the sums
    if fragment_clicks_input is None:
        fragment_clicks_input=0
    if node_clicks_input is None:
        node_clicks_input=0
    if transcript_clicks_input is None:
        transcript_clicks_input=0
    if searchbar_clicks_input is None:
        searchbar_clicks_input=0


    videoHistory=None
    try :
        #case where the student already watched the video and the history exsists for this video
        videoHistory = student.video_history_list.get(video_url=video_url_input)

        if video_watchtime_input is not None:
            videoHistory.video_watchtime= video_watchtime_input

        if notes_input is not None:
            videoHistory.notes= notes_input

        if fragments_input is not None:
            if videoHistory.fragments_progress is not None:
                videoHistory.fragments_progress.delete()
            for item in fragments_input:
                new_fragment = Fragment(name = item['name'], start= item['start'], end= item['end'], progress=item['progress'])
                videoHistory.fragments_progress.append(new_fragment)


        videoHistory.fragment_clicks = videoHistory.fragment_clicks + fragment_clicks_input
        videoHistory.node_clicks = videoHistory.node_clicks + node_clicks_input
        videoHistory.transcript_clicks = videoHistory.transcript_clicks + transcript_clicks_input
        videoHistory.searchbar_clicks = videoHistory.searchbar_clicks + searchbar_clicks_input
        videoHistory.lastChangesDate = datetime.now()

        new_log = HistoryLog(date = datetime.now(), request = str(request.json) )
        videoHistory.logs.append(new_log)

    except:

        #case where the student have not already watched the video, we need to create a VideoHistory object for this video

        if video_watchtime_input is None:
            video_watchtime_input=0

        if notes_input is None:
            notes_input=''



        videoHistory = VideoHistory(video_url = video_url_input, video_watchtime = video_watchtime_input, fragment_clicks = fragment_clicks_input, node_clicks = node_clicks_input, transcript_clicks = transcript_clicks_input,  searchbar_clicks = searchbar_clicks_input, notes = notes_input, lastChangesDate = datetime.now())

        new_log = HistoryLog(date = datetime.now(), request = str(request.json) )
        videoHistory.logs.append(new_log)

        if fragments_input is not None:
            for item in fragments_input:
                new_fragment = Fragment(name = item['name'], start= item['start'], end= item['end'], progress=item['progress'])
                videoHistory.fragments_progress.append(new_fragment)

        student.video_history_list.append(videoHistory)

    student.save()

    #store global video statistics
    videoStatistics = VideoStatistics.objects(video_url = video_url_input).first()

    if videoStatistics is None :
        videoStatistics = VideoStatistics(video_url = video_url_input, total_fragment_clicks = fragment_clicks_input, total_node_clicks = node_clicks_input, total_transcript_clicks = transcript_clicks_input,  total_searchbar_clicks = searchbar_clicks_input, amountViewers = 1)
        videoStatistics.viewersList.append(student.email)

    else:
        videoStatistics.total_fragment_clicks = videoStatistics.total_fragment_clicks + fragment_clicks_input
        videoStatistics.total_node_clicks = videoStatistics.total_node_clicks + node_clicks_input
        videoStatistics.total_transcript_clicks = videoStatistics.total_transcript_clicks + transcript_clicks_input
        videoStatistics.total_searchbar_clicks = videoStatistics.total_searchbar_clicks + searchbar_clicks_input

        if videoStatistics.viewersList.count(student.email)==0 :
            videoStatistics.viewersList.append(student.email)
            videoStatistics.amountViewers = videoStatistics.amountViewers + 1


    videoStatistics.save()
    return (jsonify({'email': student.email}), 201)

change_name_and_surname()

Change student's name and surname.

Returns:

Type Description
Response

JSON response with the student's email, new name, and new surname

Source code in apps/augmentator/src/flask-server/main.py
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
@app.route('/api/change_name_and_surname', methods=['POST'])
@auth.login_required
#the above line require that the credentials (mail/password or token) are sent in the request to login th user
def change_name_and_surname():
    """
    Change student's name and surname.

    Returns
    -------
    flask.Response
        JSON response with the student's email, new name, and new surname
    """
    name_input = request.json.get('name')
    surname_input = request.json.get('surname')
    if name_input is None or surname_input is None:
        abort(400, "The new name or/and the new surname is/are missing")    # missing arguments
    student= g.student
    student.name = name_input
    student.surname = surname_input
    student.save()
    return (jsonify({'email': student.email, 'newName': name_input, 'newSurname': surname_input}), 201)

generate_code(N=6)

Generates a random string of length N composed of lowercase letters and numbers.

Parameters:

Name Type Description Default
N int

The length of the generated string (default is 6).

6

Returns:

Type Description
str

The generated random string.

Source code in apps/augmentator/src/flask-server/main.py
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
def generate_code(N=6):
    """
    Generates a random string of length N composed of lowercase letters and numbers.

    Parameters
    ----------
    N : int, optional
        The length of the generated string (default is 6).

    Returns
    -------
    str
        The generated random string.
    """
    return ''.join(random.choice(string.ascii_lowercase + string.digits) for _ in range(N))

get_auth_token()

Get authentication token.

Returns:

Type Description
Response

JSON response with the token, duration, name, and surname

Source code in apps/augmentator/src/flask-server/main.py
797
798
799
800
801
802
803
804
805
806
807
808
809
@app.route('/api/token')
@auth.login_required
def get_auth_token():
    """
    Get authentication token.

    Returns
    -------
    flask.Response
        JSON response with the token, duration, name, and surname
    """
    token = g.student.generate_auth_token()
    return jsonify({'token': token, 'duration': None, 'name': g.student.name, 'surname':g.student.surname})

get_catalog()

Get list of all available videos in the database.

Returns:

Type Description
Response

JSON response with the video catalog

Source code in apps/augmentator/src/flask-server/main.py
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
@app.route('/api/get_catalog')
@auth.login_required
def get_catalog():
    """
    Get list of all available videos in the database.

    Returns
    -------
    flask.Response
        JSON response with the video catalog
    """
    graphs = Graphs.objects()
    videos = Videos.objects()

    catalog = []

    for v in videos:
        for gr in graphs:
            if v.video_id == gr.video_id:
                if v not in catalog:
                    catalog.append(v)


    return (jsonify({'catalog': catalog}), 201)

get_fragments(video_id)

Get video fragments and their progress.

Parameters:

Name Type Description Default
video_id str

Identifier for the video

required

Returns:

Type Description
Response

JSON response with the student's email, fragments, and keywords

Source code in apps/augmentator/src/flask-server/main.py
 985
 986
 987
 988
 989
 990
 991
 992
 993
 994
 995
 996
 997
 998
 999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
@app.route('/api/get_fragments/<string:video_id>')
@auth.login_required
def get_fragments(video_id):
    """
    Get video fragments and their progress.

    Parameters
    ----------
    video_id : str
        Identifier for the video

    Returns
    -------
    flask.Response
        JSON response with the student's email, fragments, and keywords
    """
    student= g.student
    video_url = "https://www.youtube.com/watch?v=%s" % video_id
    video_fragment_progress = None
    for i in student.video_history_list:
        if video_url == i.video_url:
            '''print(i.fragments_progress)
            for e in i.fragments_progress:
                print(e.name)'''

            video_fragment_progress = i.fragments_progress
    graph_object = Graphs.objects(video_id = video_id, email = student.email).first()

    #if user first time on this video open first available video
    if(graph_object is None):
        graph_object = Graphs.objects(video_id = video_id).first()

    #if then graph still not exist show msg
    if graph_object is None:
        abort(409, "Unexisting graph for this video id")    # the video doesn't exist in the graphs collection

    keywords = handle_data.get_definitions_fragments(graph_object.email, video_id, video_fragment_progress)

    if(video_fragment_progress is None or not len(video_fragment_progress)):

        video = Videos.objects(video_id = video_id).first()

        #if then video not exist show msg
        if video is None:
            abort(409, "video not in the catalog")    # the video is not in the catalog

        segment_amount = len(video.segment_starts)
        video_fragment_progress = []

        '''if video_id =="sXLhYStO0m8":
            names = ["Sex determination Pelvis Sciatic notch", "Pre-auricular sulcus Ventral arc Iliopubic ramus","Skull","Eye sockets", "Forehead Mastoid process Posterior zygomatich arch", "Nuchal crest", "Femur"]
            for i in range(segment_amount):
                video_fragment_progress.append({'name': names[i], 'start' : time.strftime('%H:%M:%S', time.gmtime(int(round(video.segment_starts[i])))),  'end' : time.strftime('%H:%M:%S', time.gmtime(int(round(video.segment_ends[i])))), 'progress':0 })

        else:'''

        for i in range(segment_amount):
            video_fragment_progress.append({'name': 'Part %s'%(i+1), 'start' : time.strftime('%H:%M:%S', time.gmtime(int(round(video.segment_starts[i])))),  'end' : time.strftime('%H:%M:%S', time.gmtime(int(round(video.segment_ends[i])))), 'progress':0 })



    return (jsonify({'email': student.email, 'fragments' : video_fragment_progress, 'keywords':keywords}), 201)

get_graph(video_id=None)

Get complete JSON graph for a video.

Parameters:

Name Type Description Default
video_id str

Identifier for the video

None

Returns:

Type Description
Response

JSON response with the student's email, graph, and concept vocabulary

Source code in apps/augmentator/src/flask-server/main.py
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
@app.route('/api/get_graph/<string:video_id>')
@auth.login_required
def get_graph(video_id=None):
    """
    Get complete JSON graph for a video.

    Parameters
    ----------
    video_id : str, optional
        Identifier for the video

    Returns
    -------
    flask.Response
        JSON response with the student's email, graph, and concept vocabulary
    """
    if video_id is None:
        abort(400, "The video id is missing")    # missing arguments
    student= g.student
    graph_object = Graphs.objects(video_id = video_id, email=student.email).first()

    #if user first time on this video open first available video
    if(graph_object is None):
        graph_object = Graphs.objects(video_id = video_id).first()

    #if then graph still not exist show msg
    if graph_object is None:
        abort(409, "Unexisting graph for this video id")    # the video doesn't exist in the graphs collection

    if graph_object.conceptVocabulary is None:
        graph_object.conceptVocabulary = False

    return (jsonify({'email': student.email, 'graph' : graph_object.graph, 'conceptVocabulary': graph_object.conceptVocabulary}), 201)

get_history()

Get user's video history.

Returns:

Type Description
Response

JSON response with the student's email, video history, and video titles

Source code in apps/augmentator/src/flask-server/main.py
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
@app.route('/api/get_user_history')
@auth.login_required
def get_history():
    """
    Get user's video history.

    Returns
    -------
    flask.Response
        JSON response with the student's email, video history, and video titles
    """
    student:Student = g.student
    video_title_list = []

    # Removing videos that have been removed from videos collection
    for video_in_history in reversed(student.video_history_list):
        if not Videos.objects(video_id = video_in_history.video_url.split("watch?v=")[1]):
            student.video_history_list.remove(video_in_history)

    history_list = student.get_sorted_history(by="lastChange")

    for video in history_list:
        video_title_list.append(get_video_title_from_url(video.video_url.split("watch?v=")[1]))
        #print(video," ",get_video_title_from_url(video.video_url.split("watch?v=")[1]))

    return (jsonify({'email': student.email, 'videoHistory' : history_list, 'videoHistoryTitles': video_title_list}), 201)

get_image(video_id=None, fragment_index=None)

Get image of a video fragment.

Parameters:

Name Type Description Default
video_id str

Identifier for the video

None
fragment_index int

Index of the fragment

None

Returns:

Type Description
Response

Image file response

Source code in apps/augmentator/src/flask-server/main.py
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
@app.route("/api/get_image/<string:video_id>/<int:fragment_index>")
def get_image(video_id=None, fragment_index=None ):
    """
    Get image of a video fragment.

    Parameters
    ----------
    video_id : str, optional
        Identifier for the video
    fragment_index : int, optional
        Index of the fragment

    Returns
    -------
    flask.Response
        Image file response
    """
    if video_id is None or fragment_index is None:
        abort(400, "The video id or the image name is missing")    # missing arguments

    #get the starting time of the segment to know the image file name
    video = Videos.objects(video_id = video_id).first()
    if video is None:
        abort(409, "video not in the catalog")    # the video doesn't exist

    #segment_starting_time = None
    #try :
    #    segment_starting_time = video.segment_starts[fragment_index]
    #except IndexError:
    #    abort(409, "fragment index out of range ")

    #image_name = str(segment_starting_time).replace('.','_')+'.jpg'
    image_name = str(fragment_index).replace('.','_')+'.jpg'
    try:
        return send_from_directory(app.config["CLIENT_IMAGES"]+sep+video_id, image_name, as_attachment=True)
    except FileNotFoundError:
        abort

get_integer_part(number)

Get the integer part of a number.

Parameters:

Name Type Description Default
number float

Input number

required

Returns:

Type Description
float

Integer part of the number

Source code in apps/augmentator/src/flask-server/main.py
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
def get_integer_part(number):
    """
    Get the integer part of a number.

    Parameters
    ----------
    number : float
        Input number

    Returns
    -------
    float
        Integer part of the number
    """
    split_number = math.modf(number)
    return split_number[1]

get_student()

Get student's name, surname, and email.

Returns:

Type Description
Response

JSON response with the student's name, surname, and email

Source code in apps/augmentator/src/flask-server/main.py
783
784
785
786
787
788
789
790
791
792
793
794
@app.route('/api/get_user_infos')
@auth.login_required
def get_student():
    """
    Get student's name, surname, and email.

    Returns
    -------
    flask.Response
        JSON response with the student's name, surname, and email
    """
    return jsonify({'name': g.student.name, 'surname':g.student.surname, 'email': g.student.email})

get_video_title_from_url(video_id)

Get YouTube video title based on video ID.

Parameters:

Name Type Description Default
video_id str

YouTube video ID

required

Returns:

Type Description
str

Video title

Source code in apps/augmentator/src/flask-server/main.py
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
def get_video_title_from_url(video_id):
    """
    Get YouTube video title based on video ID.

    Parameters
    ----------
    video_id : str
        YouTube video ID

    Returns
    -------
    str
        Video title
    """
    #print("GET VIDEO: ",video_id)
    params = {"format": "json", "url": "https://www.youtube.com/watch?v=%s" % video_id}
    url = "https://www.youtube.com/oembed"
    query_string = urllib.parse.urlencode(params)
    url = url + "?" + query_string
    #print("url ",url)

    #print("dopo")

    with urllib.request.urlopen(url) as response:
        response_text = response.read()
        data = json.loads(response_text.decode())
    return data['title']

graph(annotator_id, video_id)

Get graph for a given video and annotator.

Parameters:

Name Type Description Default
annotator_id str

Identifier for the annotator

required
video_id str

Identifier for the video

required

Returns:

Type Description
dict

Dictionary containing concepts list and concept vocabulary

Source code in apps/augmentator/src/flask-server/main.py
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
@app.route('/api/graph/<annotator_id>/<video_id>')
@auth.login_required
def graph(annotator_id, video_id):
    """
    Get graph for a given video and annotator.

    Parameters
    ----------
    annotator_id : str
        Identifier for the annotator
    video_id : str
        Identifier for the video

    Returns
    -------
    dict
        Dictionary containing concepts list and concept vocabulary
    """
    concept_graph = data.build_array(annotator_id, video_id)

    # old: return {"conceptsList": concept_graph }

    conceptVocabulary = data.get_concept_vocabulary(annotator_id, video_id)

    # If the concept vocabulary is new (empty) in DB then initialize it to empty synonyms
    if(conceptVocabulary == None) :
        conceptVocabulary = {}
        concept_list = data.get_concept_list(annotator_id, video_id)
        for c in concept_list:
            conceptVocabulary[c["name"][4:].replace("_", " ")] = []    

    return {"conceptsList": concept_graph, "conceptVocabulary": conceptVocabulary}

graph_id(video_id)

Get graph user IDs for a given video.

Parameters:

Name Type Description Default
video_id str

Identifier for the video

required

Returns:

Type Description
dict

Dictionary containing list of graph IDs

Source code in apps/augmentator/src/flask-server/main.py
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
@app.route('/api/graph_id/<video_id>')
@auth.login_required
def graph_id(video_id):
    """
    Get graph user IDs for a given video.

    Parameters
    ----------
    video_id : str
        Identifier for the video

    Returns
    -------
    dict
        Dictionary containing list of graph IDs
    """
    print("***** EKEEL - Video Augmentation: main.py::graph_id(): Inizio ******")
    student= g.student
    graph_list = handle_data.check_graphs(video_id,student.email)

    # if user first time on this video, select all available graph ids
    if not len(graph_list):
        graph_list = handle_data.get_graphs(video_id)
    print(graph_list)
    print("***** EKEEL - Video Augmentation: main.py::graph_id(): Fine ******")

    return {"graphs_id_list": graph_list }

new_student()

Register a new student account.

Returns:

Type Description
Response

JSON response with the student's email

Source code in apps/augmentator/src/flask-server/main.py
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
@app.route('/api/register', methods=['POST'])
def new_student():
    """
    Register a new student account.

    Returns
    -------
    flask.Response
        JSON response with the student's email
    """
    email_input = request.json.get('email')
    password_input = request.json.get('password')
    name_input = request.json.get('name')
    surname_input = request.json.get('surname')
    if email_input is None or password_input is None or name_input is None or surname_input is None:
        abort(400)    # missing arguments
    if Student.objects(email=email_input).first() is not None:
        abort(409, "An account have already been created with this mail")    # existing student
    existingUnverifiedStudent = UnverifiedStudent.objects(email=email_input).first()
    if existingUnverifiedStudent is not None:
        existingUnverifiedStudent.delete()

    generated_code_creation = generate_code()
    # create an UnverifiedStudent and save it in the db
    unverifiedStudent = UnverifiedStudent(email=email_input, name= name_input, surname = surname_input,nb_try_code_on_creation = 0)
    unverifiedStudent.hash_password(password_input)
    unverifiedStudent.hash_code_on_creation(generated_code_creation)
    unverifiedStudent.save()

    #send a mail with the verification code
    msg = Message('EKEEL- Code to finalize your account creation', recipients = [email_input])
    msg.body = "Hello, welcome to EKEEL ! \n Your validation code to finalize your account creation : "+ generated_code_creation
    try:
        mail.send(msg)
    except SMTPRecipientsRefused:
        abort(406,"invalid mail")
    except :
        abort(503, "error returned by the email sending service")
    return (jsonify({'email': unverifiedStudent.email}), 201)

send_code_to_delete_account_by_mail()

Send code to delete account via email.

Returns:

Type Description
Response

JSON response with the student's email

Source code in apps/augmentator/src/flask-server/main.py
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
@app.route('/api/delete_account', methods=['POST'])
@auth.login_required
def send_code_to_delete_account_by_mail():
    """
    Send code to delete account via email.

    Returns
    -------
    flask.Response
        JSON response with the student's email
    """
    email_input = request.json.get('email')
    if email_input is None:
        abort(400)    # missing arguments
    student = Student.objects(email=email_input).first()
    if student is None:
        abort(409, "No account associated with this mail")    # no existing student
    generated_code_delete_account = generate_code()
    student.hash_code_delete_account(generated_code_delete_account)
    student.save()

    #send a mail with the verification code
    msg = Message('EKEEL- Code to delete your account', recipients = [email_input])
    msg.body = "Hello ! \n Here is your validation code to delete your account : "+ generated_code_delete_account+"\n Be carefull, account deletion can't be undone"
    mail.send(msg)
    return (jsonify({'email': student.email}), 201)

send_code_to_reset_password_by_mail()

Send code to reset password via email.

Returns:

Type Description
Response

JSON response with the student's email

Source code in apps/augmentator/src/flask-server/main.py
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
@app.route('/api/retrieve_password', methods=['POST'])
def send_code_to_reset_password_by_mail():
    """
    Send code to reset password via email.

    Returns
    -------
    flask.Response
        JSON response with the student's email
    """
    email_input = request.json.get('email')
    if email_input is None:
        abort(400)    # missing arguments
    student = Student.objects(email=email_input).first()
    if student is None:
        abort(409, "No account associated with this mail")    # no existing student
    generated_code_reset_password = generate_code()
    student.hash_code_reset_password(generated_code_reset_password)
    student.save()

    #send a mail with the verification code
    msg = Message('EKEEL- Code to change your password', recipients = [email_input])
    msg.body = "Hello ! \n Here is your validation code to change your password : "+ generated_code_reset_password
    mail.send(msg)
    return (jsonify({'email': student.email}), 201)

sparql_query_concepts(video_id, annotator_id)

Perform SPARQL query for concepts.

Parameters:

Name Type Description Default
video_id str

Identifier for the video

required
annotator_id str

Identifier for the annotator

required
Source code in apps/augmentator/src/flask-server/main.py
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
@app.route('/api/sparql_query_concepts/<video_id>')
@auth.login_required
def sparql_query_concepts(video_id, annotator_id):
    """
    Perform SPARQL query for concepts.

    Parameters
    ----------
    video_id : str
        Identifier for the video
    annotator_id : str
        Identifier for the annotator
    """
    client = pymongo.MongoClient(
        "mongodb+srv://"+MONGO_CLUSTER_USERNAME+":"+MONGO_CLUSTER_PASSWORD+"@clusteredurell.z8aeh.mongodb.net/edurell?retryWrites=true&w=majority")

    db = client.ekeel
    collection = db.graphs

    query = {
        "annotator_id": annotator_id,
        "video_id": video_id
    }

    general_query = {
        "video_id": video_id
    }

    #se trova un grafo qualunque con quel video_id, salva il risultato della query
    if collection.find_one(general_query) is not None:
        risultato = collection.find_one(general_query)["conceptVocabulary"]
    #ma se trova il grafo con quel video_id e proprio con quell'annotator_id, sovrascrive risultato
    if collection.find_one(query) is not None:
        risultato = collection.find_one(query)["conceptVocabulary"]    

    #se almeno una delle due query รจ andata a buon fine
    if risultato is not None:
        gr = Graph()\
        .parse(data=json.dumps(risultato), format='json-ld')

        tic = time.time()

        # Seleziona tutti i nodi concetto ed eventuali sinonimi
        query3 = """
            PREFIX oa: <http://www.w3.org/ns/oa#>
            PREFIX edu: <https://teldh.github.io/edurell#>
            PREFIX dctypes: <http://purl.org/dc/dcmitype/>

            SELECT ?concept ?synonym
            WHERE {
                    ?concetto skos:prefLabel ?concept.
                    OPTIONAL {
                        ?concetto skos:altLabel ?synonym
                    }
                    FILTER (!BOUND(?altLabel))
                }"""

        qres = gr.query(query3)

        toc = time.time()

        #print per i concetti
        print("Results: - obtained in %.4f seconds" % (toc - tic))
        for row in qres: 
            print(f"Concept: {row.concept} || Synonym: {row.synonym}")

sparql_query_definitions(video_id, annotator_id)

Perform SPARQL query for definitions.

Parameters:

Name Type Description Default
video_id str

Identifier for the video

required
annotator_id str

Identifier for the annotator

required
Source code in apps/augmentator/src/flask-server/main.py
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
def sparql_query_definitions(video_id, annotator_id):
    """
    Perform SPARQL query for definitions.

    Parameters
    ----------
    video_id : str
        Identifier for the video
    annotator_id : str
        Identifier for the annotator
    """
    client = pymongo.MongoClient(
        "mongodb+srv://"+MONGO_CLUSTER_USERNAME+":"+MONGO_CLUSTER_PASSWORD+"@clusteredurell.z8aeh.mongodb.net/edurell?retryWrites=true&w=majority")

    db = client.ekeel
    collection = db.graphs

    query = {
        "annotator_id": annotator_id,
        "video_id": video_id
    }

    general_query = {
        "video_id": video_id
    }

    #se trova un grafo qualunque con quel video_id, salva il risultato della query
    if collection.find_one(general_query) is not None:
        risultato = collection.find_one(general_query)["graph"]
    #ma se trova il grafo con quel video_id e proprio con quell'annotator_id, sovrascrive risultato
    if collection.find_one(query) is not None:
        risultato = collection.find_one(query)["graph"]    

    #se almeno una delle due query รจ andata a buon fine
    if risultato is not None:
        gr = Graph()\
        .parse(data=json.dumps(risultato), format='json-ld')

        tic = time.time()

        # Seleziona i concetti che sono spiegati nel video
        query1 = """
            PREFIX oa: <http://www.w3.org/ns/oa#>
            PREFIX edu: <https://teldh.github.io/edurell#>
            PREFIX dctypes: <http://purl.org/dc/dcmitype/>
            PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>

            SELECT ?explained_concept ?created ?creator ?description_type
            WHERE {
                    ?concept_definition oa:motivatedBy oa:describing.
                    ?concept_definition dcterms:created ?created.
                    ?concept_definition dcterms:creator ?creator.
                    ?concept_definition oa:hasBody ?explained_concept.
                    ?concept_definition skos:note ?description_type.
                    ?concept_definition oa:hasTarget ?target.
                    ?target oa:hasSelector ?selector.
                    ?selector oa:hasStartSelector ?startSelector

                }"""


        qres = gr.query(query1)

        toc = time.time()

        #print per le definizioni
        print("Results: - obtained in %.4f seconds" % (toc - tic))
        for row in qres:
            print(f"Explained concept: {row.explained_concept}")
            print(f"Created: {row.created}")
            print(f"Creator: {row.creator}")
            print(f"Description Type: {row.description_type}")

sparql_query_prerequisite(video_id, annotator_id)

Perform SPARQL query for prerequisites.

Parameters:

Name Type Description Default
video_id str

Identifier for the video

required
annotator_id str

Identifier for the annotator

required
Source code in apps/augmentator/src/flask-server/main.py
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
def sparql_query_prerequisite(video_id, annotator_id):
    """
    Perform SPARQL query for prerequisites.

    Parameters
    ----------
    video_id : str
        Identifier for the video
    annotator_id : str
        Identifier for the annotator
    """
    client = pymongo.MongoClient(
        "mongodb+srv://"+MONGO_CLUSTER_USERNAME+":"+MONGO_CLUSTER_PASSWORD+"@clusteredurell.z8aeh.mongodb.net/edurell?retryWrites=true&w=majority")

    db = client.ekeel
    collection = db.graphs

    query = {
        "annotator_id": annotator_id,
        "video_id": video_id
    }

    general_query = {
        "video_id": video_id
    }

    #se trova un grafo qualunque con quel video_id, salva il risultato della query
    if collection.find_one(general_query) is not None:
        risultato = collection.find_one(general_query)["graph"]
    #ma se trova il grafo con quel video_id e proprio con quell'annotator_id, sovrascrive risultato
    if collection.find_one(query) is not None:
        risultato = collection.find_one(query)["graph"]    

    #se almeno una delle due query รจ andata a buon fine
    if risultato is not None:
        gr = Graph()\
        .parse(data=json.dumps(risultato), format='json-ld')

        tic = time.time()

        #query per i prerequisiti
        query2 = """
            PREFIX oa: <http://www.w3.org/ns/oa#>
            PREFIX edu: <https://teldh.github.io/edurell#>

            SELECT ?prerequisite_concept ?created ?creator ?prerequisite_type ?target_concept
            WHERE {
                    ?concept_prerequisite oa:motivatedBy edu:linkingPrerequisite.
                    ?concept_prerequisite dcterms:created ?created.
                    ?concept_prerequisite dcterms:creator ?creator.
                    ?concept_prerequisite oa:hasBody ?prerequisite_concept.
                    ?concept_prerequisite skos:note ?prerequisite_type.
                    ?concept_prerequisite oa:hasTarget ?target.
                    ?target dcterms:subject ?target_concept.
                }"""


        qres = gr.query(query2)

        toc = time.time()

        #print per i prerequisiti
        print("Results: - obtained in %.4f seconds" % (toc - tic))
        for row in qres: 
            print(f"Prerequisite concept: {row.prerequisite_concept}")
            print(f"Created: {row.created}")
            print(f"Creator: {row.creator}")
            print(f"Prerequisite Type: {row.prerequisite_type}")
            print(f"Target concept: {row.target_concept}")

speech_from_youtube()

Retrieves the speech transcript from a YouTube video URL.

Parameters:

Name Type Description Default
None
required

Returns:

Type Description
Response

A JSON response containing the speech transcript and video metadata.

Source code in apps/augmentator/src/flask-server/main.py
 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
@app.route('/api/youtube_transcript', methods=["GET", "POST"])
def speech_from_youtube():
    """
    Retrieves the speech transcript from a YouTube video URL.

    Parameters
    ----------
    None

    Returns
    -------
    flask.Response
        A JSON response containing the speech transcript and video metadata.
    """
    req = request.get_json(force=True)
    videoId=req.get('video_id')

    collection = pymongo.MongoClient(
        "mongodb+srv://"+MONGO_CLUSTER_USERNAME+":"+MONGO_CLUSTER_PASSWORD+"@clusteredurell.z8aeh.mongodb.net/edurell?retryWrites=true&w=majority").ekeel.videos

    video_metadata = collection.find_one({"video_id": videoId})
    languages = []
    if video_metadata is not None and "language" in video_metadata.keys():
        languages.append(video_metadata["language"])
    languages.append("en")
    transcript = YouTubeTranscriptApi.get_transcript(videoId, languages=languages)
    subs_dict = []
    for sub in transcript:
        start = get_integer_part(sub["start"])
        duration = get_integer_part(sub["duration"])
        subs_dict.append(
            {
                "text": sub["text"],
                "start": start,
                "end": start + duration
            }
        )
    result = jsonify(subs_dict)
    return result

testm(video_id)

Test function for querying video data.

Parameters:

Name Type Description Default
video_id str

Identifier for the video

required

Returns:

Type Description
dict

Dictionary containing query results

Source code in apps/augmentator/src/flask-server/main.py
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
@app.route('/api/testm/<video_id>')
@auth.login_required
def testm(video_id):
    """
    Test function for querying video data.

    Parameters
    ----------
    video_id : str
        Identifier for the video

    Returns
    -------
    dict
        Dictionary containing query results
    """
    client = pymongo.MongoClient(
        "mongodb+srv://"+MONGO_CLUSTER_USERNAME+":"+MONGO_CLUSTER_PASSWORD+"@clusteredurell.z8aeh.mongodb.net/edurell?retryWrites=true&w=majority")

    db = client.ekeel
    collection = db.graphs

    cursor = collection.find({"video_id": video_id})
    gr = Graph()
    retval={}
    for document in cursor:
        print("asd")
        if document is not None:

            gr.parse(data=json.dumps(document["graph"]), format='json-ld')


            qr = """
                PREFIX oa: <http://www.w3.org/ns/oa#>
                PREFIX edu: <https://teldh.github.io/edurell#>
                PREFIX dctypes: <http://purl.org/dc/dcmitype/>
                PREFIX dcterms: <http://purl.org/dc/terms/>

                SELECT ?sub ?pre ?obj
                WHERE {
                        ?sub ?pre ?obj

                    }

            """

            qr2="""
                PREFIX oa: <http://www.w3.org/ns/oa#>
                PREFIX edu: <https://teldh.github.io/edurell#>
                PREFIX dctypes: <http://purl.org/dc/dcmitype/>
                PREFIX dcterms: <http://purl.org/dc/terms/>

                SELECT ?sub  ?obj
                WHERE {
                        ?sub dcterms:created ?obj

                    }

            """
            qres = gr.query(qr)
            qres2=gr.query(qr2)
            resulto={}
            resulto2={}
            print("STARTOOOOOO ",qres)
            for idx,row in enumerate(qres):
                resulto[idx]={"subject":row['sub'],"predicate":row['pre'],"object":row['obj']}
            print("ENDOOOOOOOO")
            for idx,row in enumerate(qres2):
                resulto2[idx]={"subject":row['sub'],"object":row['obj']}
            retval["res"]=resulto
    return retval

verify_code_and_change_password()

Verify code and change password.

Returns:

Type Description
Response

JSON response with the student's email

Source code in apps/augmentator/src/flask-server/main.py
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
@app.route('/api/retrieve_password/verify', methods=['POST'])
def verify_code_and_change_password():
    """
    Verify code and change password.

    Returns
    -------
    flask.Response
        JSON response with the student's email
    """
    email_input = request.json.get('email')
    code_input = request.json.get('code')
    new_password_input = request.json.get('password')
    if email_input is None or code_input is None:
        abort(400, "The code or the email is missing")    # missing arguments
    student = Student.objects(email=email_input).first()
    if student is None:
        abort(409, "No account exists with this mail")    # no existing student
    if not student.verify_code_reset_password(code_input):
        if student.nb_try_code_reset_password is not None and student.nb_try_code_reset_password>5:
            student.code_reset_password = None
            student.nb_try_code_reset_password = None
            student.save()
            abort(403, "Too many wrong validation codes, please restart the password retrieval procedure")
        abort(401, "Wrong validation code")

    else:
        student.hash_password(new_password_input)
        student.code_reset_password = None
        student.nb_try_code_reset_password = None
        student.save()
        return (jsonify({'email': student.email}), 201)

verify_code_and_delete_account()

Verify code and delete account.

Returns:

Type Description
Response

JSON response with the student's email

Source code in apps/augmentator/src/flask-server/main.py
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
@app.route('/api/delete_account/verify', methods=['POST'])
@auth.login_required
def verify_code_and_delete_account():
    """
    Verify code and delete account.

    Returns
    -------
    flask.Response
        JSON response with the student's email
    """
    email_input = request.json.get('email')
    code_input = request.json.get('code')
    if email_input is None or code_input is None:
        abort(400, "The code or the email is missing")    # missing arguments
    student = Student.objects(email=email_input).first()
    if student is None:
        abort(409, "No account exists with this mail")    # no existing student
    if not student.verify_code_delete_account(code_input):
        if student.nb_try_code_delete_account is not None and student.nb_try_code_delete_account>5:
            student.code_delete_account = None
            student.nb_try_code_delete_account = None
            student.save()
            abort(403, "Too many wrong validation codes, please restart the account deletion procedure")
        abort(415, "Wrong validation code")

    else:
        data.delete_graphs(email_input)
        student.delete()
        return (jsonify({'email': student.email}), 201)

verify_mail()

Verify email and code for account creation.

Returns:

Type Description
Response

JSON response with the student's email

Source code in apps/augmentator/src/flask-server/main.py
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
@app.route('/api/register/verify', methods=['POST'])
def verify_mail():
    """
    Verify email and code for account creation.

    Returns
    -------
    flask.Response
        JSON response with the student's email
    """
    email_input = request.json.get('email')
    code_input = request.json.get('code')
    if email_input is None or code_input is None:
        abort(400, "The code or the email is missing")    # missing arguments
    if Student.objects(email=email_input).first() is not None:
        abort(409,"An account have already been created with this mail")    # existing student
    unverifiedStudent = UnverifiedStudent.objects(email=email_input).first()
    if unverifiedStudent is None:
        abort(404, "No temporary student found, please restart register from the beginning")    # not existing UnverifiedStudent
    if not unverifiedStudent.verify_code_on_creation(code_input):
        if unverifiedStudent.nb_try_code_on_creation is not None and unverifiedStudent.nb_try_code_on_creation>5:
            unverifiedStudent.delete()
            abort(403, "Too many wrong validation code, please restart register from the beginning")
        abort(401, "Wrong validation code")

    #after the checks have passed, create a Student in the db and delete the UnverifiedStudent from the db
    student = Student(email = unverifiedStudent.email, name = unverifiedStudent.name, surname = unverifiedStudent.surname, password_hash = unverifiedStudent.password_hash)
    student.save()
    unverifiedStudent.delete()
    return (jsonify({'email': student.email}), 201)

verify_password(email_or_token, password)

Verify user password or token for authentication.

Parameters:

Name Type Description Default
email_or_token str

Email or authentication token

required
password str

User password

required

Returns:

Type Description
bool

True if authentication is successful, False otherwise

Source code in apps/augmentator/src/flask-server/main.py
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
@auth.verify_password
def verify_password(email_or_token, password):
    """
    Verify user password or token for authentication.

    Parameters
    ----------
    email_or_token : str
        Email or authentication token
    password : str
        User password

    Returns
    -------
    bool
        True if authentication is successful, False otherwise
    """
    # first try to authenticate by token
    student = Student.verify_auth_token(email_or_token)
    if not student:
        # try to authenticate with email/password
        student = Student.objects(email=email_or_token).first()
        if not student or not student.verify_password(password):
            return False
    g.student = student
    return True