Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
Kontr 2.0
Portal API Backend
Commits
c0a95638
Verified
Commit
c0a95638
authored
Oct 06, 2018
by
Peter Stanko
Browse files
Clients endpoint updated for type selection
parent
6b8f2b86
Changes
7
Hide whitespace changes
Inline
Side-by-side
management/data/data_test.py
View file @
c0a95638
...
...
@@ -43,10 +43,12 @@ def init_test_data(app: Flask, db: SQLAlchemy):
tc1_student
=
factory
.
scaffold_role
(
role_type
=
'student'
,
course
=
test_course1
)
tc1_teacher
=
factory
.
scaffold_role
(
role_type
=
'teacher'
,
course
=
test_course1
)
tc1_owner
=
factory
.
scaffold_role
(
role_type
=
'owner'
,
course
=
test_course1
)
tc1_workers
=
factory
.
scaffold_role
(
role_type
=
'worker'
,
course
=
test_course1
)
tc2_student
=
factory
.
scaffold_role
(
role_type
=
'student'
,
course
=
test_course2
)
tc2_teacher
=
factory
.
scaffold_role
(
role_type
=
'teacher'
,
course
=
test_course2
)
tc2_owner
=
factory
.
scaffold_role
(
role_type
=
'owner'
,
course
=
test_course2
)
tc2_workers
=
factory
.
scaffold_role
(
role_type
=
'worker'
,
course
=
test_course2
)
# relationships
teacher_student
=
teacher1
...
...
@@ -111,6 +113,8 @@ def init_test_data(app: Flask, db: SQLAlchemy):
processing
=
factory
.
create_worker
(
name
=
'processing'
,
url
=
"bar/url"
)
processing
.
secrets
.
append
(
Secret
(
'processing_secret'
,
"processing_secret"
,
time
.
current_time
()
+
timedelta
(
hours
=
1
)))
executor
.
roles
.
append
(
tc1_workers
)
processing
.
roles
.
append
(
tc2_workers
)
db
.
session
.
add_all
([
executor
,
processing
])
# Commit to the DB
db
.
session
.
commit
()
portal/database/models.py
View file @
c0a95638
...
...
@@ -310,6 +310,13 @@ class User(EntityBase, Client):
return
hash
(
self
.
id
)
def
_get_class_based_on_client_type
(
client_type
):
klass
=
Client
if
client_type
is
not
None
:
klass
=
User
if
client_type
==
ClientType
.
USER
else
Worker
return
klass
class
Course
(
db
.
Model
,
EntityBase
,
NamedMixin
):
"""Course model
Attributes:
...
...
@@ -392,11 +399,13 @@ class Course(db.Model, EntityBase, NamedMixin):
.
join
(
User
.
roles
).
filter
((
Role
.
id
==
role
.
id
)
&
(
Role
.
course
==
self
))
\
.
all
()
def
get_clients_filtered
(
self
,
groups
:
List
[
'Group'
],
roles
:
List
[
'Role'
]):
def
get_clients_filtered
(
self
,
groups
:
List
[
'Group'
]
=
None
,
roles
:
List
[
'Role'
]
=
None
,
client_type
=
None
):
"""Gets all users in the course who are members of at least one of
the provided groups and have at least one of the specified roles.
Args:
client_type:
groups(List['Group']): A list of groups. A user must be part of at least one to
be included in the result.
roles(List['Role']): A list of roles. A user must be part of at
...
...
@@ -406,13 +415,17 @@ class Course(db.Model, EntityBase, NamedMixin):
(are in at least one group AND have at least one role).
"""
query
=
Client
.
query
.
join
(
Client
.
roles
).
filter
(
Role
.
course_id
==
self
.
id
)
klass
=
_get_class_based_on_client_type
(
client_type
)
query
=
klass
.
query
.
join
(
klass
.
roles
)
if
client_type
is
not
None
:
query
=
query
.
filter
(
klass
.
type
==
client_type
)
query
=
query
.
filter
(
Role
.
course_id
==
self
.
id
)
if
roles
:
role_ids
=
[
role
.
id
for
role
in
roles
]
query
=
query
.
filter
(
Role
.
id
.
in_
(
role_ids
))
if
groups
:
if
groups
and
client_type
==
ClientType
.
USER
:
group_ids
=
[
group
.
id
for
group
in
groups
]
query
=
query
.
join
(
Client
.
groups
).
filter
(
Group
.
id
.
in_
(
group_ids
)).
filter
(
query
=
query
.
join
(
User
.
groups
).
filter
(
Group
.
id
.
in_
(
group_ids
)).
filter
(
Group
.
course_id
==
self
.
id
)
return
query
.
all
()
...
...
portal/rest/courses.py
View file @
c0a95638
...
...
@@ -3,6 +3,7 @@ from flask_jwt_extended import jwt_required
from
flask_restplus
import
Namespace
from
portal
import
logger
from
portal.database.models
import
ClientType
from
portal.rest
import
rest_helpers
from
portal.rest.custom_resource
import
CustomResource
from
portal.rest.schemas
import
SCHEMAS
...
...
@@ -138,17 +139,63 @@ class CourseImport(CustomResource):
return
SCHEMAS
.
dump
(
'course'
,
copied_course
)
def
extract_client_type
():
client_type
=
request
.
args
.
get
(
'type'
)
if
client_type
is
not
None
:
if
client_type
==
'worker'
:
client_type
=
ClientType
.
WORKER
elif
client_type
==
'user'
:
client_type
=
ClientType
.
USER
else
:
client_type
=
None
return
client_type
@
courses_namespace
.
route
(
'/<string:cid>/clients'
)
@
courses_namespace
.
param
(
'cid'
,
'Course id'
)
@
courses_namespace
.
response
(
404
,
'Course not found'
)
class
CourseClients
(
CustomResource
):
@
jwt_required
# @courses_namespace.response(200, 'Users in the course', model=users_schema)
@
courses_namespace
.
response
(
403
,
'Not allowed to see
user
s in the course'
)
@
courses_namespace
.
response
(
403
,
'Not allowed to see
client
s in the course'
)
def
get
(
self
,
cid
):
course
=
self
.
find
.
course
(
cid
)
self
.
permissions
(
course
=
course
).
require
.
permissions
([
'view_course_full'
])
group_ids
=
request
.
args
.
getlist
(
'group'
)
role_ids
=
request
.
args
.
getlist
(
'role'
)
users
=
self
.
rest
.
courses
(
course
).
get_clients_filtered
(
group_ids
,
role_ids
)
return
SCHEMAS
.
dump
(
'users'
,
users
)
client_type
=
extract_client_type
()
clients
=
self
.
rest
.
courses
(
course
).
get_clients_filtered
(
group_ids
,
role_ids
,
client_type
=
client_type
)
return
SCHEMAS
.
dump
(
'clients'
,
clients
)
@
courses_namespace
.
route
(
'/<string:cid>/users'
)
@
courses_namespace
.
param
(
'cid'
,
'Course id'
)
@
courses_namespace
.
response
(
404
,
'Course not found'
)
class
CourseUsers
(
CustomResource
):
@
jwt_required
# @courses_namespace.response(200, 'Users in the course', model=users_schema)
@
courses_namespace
.
response
(
403
,
'Not allowed to see users in the course'
)
def
get
(
self
,
cid
):
course
=
self
.
find
.
course
(
cid
)
self
.
permissions
(
course
=
course
).
require
.
permissions
([
'view_course_full'
])
group_ids
=
request
.
args
.
getlist
(
'group'
)
role_ids
=
request
.
args
.
getlist
(
'role'
)
users
=
self
.
rest
.
courses
(
course
).
get_clients_filtered
(
group_ids
,
role_ids
,
client_type
=
ClientType
.
USER
)
return
SCHEMAS
.
dump
(
'users'
,
users
)
@
courses_namespace
.
route
(
'/<string:cid>/workers'
)
@
courses_namespace
.
param
(
'cid'
,
'Course id'
)
@
courses_namespace
.
response
(
404
,
'Course not found'
)
class
CourseWorkers
(
CustomResource
):
@
jwt_required
# @courses_namespace.response(200, 'Users in the course', model=users_schema)
@
courses_namespace
.
response
(
403
,
'Not allowed to see workers in the course'
)
def
get
(
self
,
cid
):
course
=
self
.
find
.
course
(
cid
)
self
.
permissions
(
course
=
course
).
require
.
permissions
([
'view_course_full'
])
group_ids
=
request
.
args
.
getlist
(
'group'
)
role_ids
=
request
.
args
.
getlist
(
'role'
)
workers
=
self
.
rest
.
courses
(
course
).
get_clients_filtered
(
group_ids
,
role_ids
,
client_type
=
ClientType
.
WORKER
)
return
SCHEMAS
.
dump
(
'workers'
,
workers
)
portal/rest/schemas.py
View file @
c0a95638
...
...
@@ -382,6 +382,7 @@ class Schemas:
PARAMS
=
{
'user_reduced'
:
(
*
ALWAYS_ALLOWED
,
'username'
,
'uco'
,
'email'
,
'name'
),
'users'
:
(
*
ALWAYS_ALLOWED
,
'username'
,
'uco'
,
'email'
),
'clients'
:
(
*
ALWAYS_ALLOWED
,
'codename'
,
'type'
),
'submissions'
:
(
*
ALWAYS_ALLOWED
,
'course'
,
'state'
,
'project'
,
'scheduled_for'
,
'user'
),
'submission_state'
:
(
*
ALWAYS_ALLOWED
,
'state'
,
'parameters'
,
'scheduled_for'
),
'roles'
:
ENT_W_COURSE
,
...
...
@@ -391,8 +392,11 @@ class Schemas:
'courses'
:
(
*
CODENAME_W_DESC
,),
'config_reduced'
:
(
*
ALWAYS_ALLOWED
,
'project'
,
'submissions_allowed_from'
,
'submissions_allowed_to'
,
'file_whitelist'
),
'secrets'
:
(
*
ALWAYS_ALLOWED
,
'name'
,
'expires_at'
,
'client.id'
,
'client.type'
,
'client.name'
,
'client.codename'
),
'secret'
:
(
*
ALWAYS_ALLOWED
,
'name'
,
'expires_at'
,
'client.id'
,
'client.type'
,
'client.name'
,
'client.codename'
)
'secrets'
:
(
*
ALWAYS_ALLOWED
,
'name'
,
'expires_at'
,
'client.id'
,
'client.type'
,
'client.name'
,
'client.codename'
),
'secret'
:
(
*
ALWAYS_ALLOWED
,
'name'
,
'expires_at'
,
'client.id'
,
'client.type'
,
'client.name'
,
'client.codename'
)
}
def
__get_schema
(
self
,
schema_klass
,
select_params
=
None
,
only
=
None
,
strict
=
True
,
**
kwargs
):
...
...
@@ -414,6 +418,14 @@ class Schemas:
def
users
(
self
,
**
kwargs
):
return
self
.
__get_schema
(
UserSchema
,
many
=
True
,
**
kwargs
)
@
fn_name
def
client
(
self
,
**
kwargs
):
return
self
.
__get_schema
(
ClientSchema
,
**
kwargs
)
@
fn_name
def
clients
(
self
,
**
kwargs
):
return
self
.
__get_schema
(
ClientSchema
,
many
=
True
,
**
kwargs
)
@
fn_name
def
user_reduced
(
self
,
**
kwargs
):
return
self
.
__get_schema
(
UserSchema
,
**
kwargs
)
...
...
portal/service/courses.py
View file @
c0a95638
...
...
@@ -76,7 +76,7 @@ class CourseService(GeneralService):
log
.
info
(
f
"[UPDATE] Notes access token
{
self
.
course
.
log_name
}
:
{
token
}
"
)
return
self
.
course
def
get_clients_filtered
(
self
,
groups
:
List
[
str
],
roles
:
List
[
str
])
->
List
[
User
]:
def
get_clients_filtered
(
self
,
groups
:
List
[
str
],
roles
:
List
[
str
]
,
client_type
=
None
)
->
List
[
User
]:
"""Get all users for course filtered
Args:
groups(list): Group names list
...
...
@@ -85,4 +85,5 @@ class CourseService(GeneralService):
"""
groups_entities
=
Group
.
query
.
filter
(
Group
.
id
.
in_
(
groups
)).
all
()
if
groups
else
None
roles_entities
=
Role
.
query
.
filter
(
Role
.
id
.
in_
(
roles
)).
all
()
if
roles
else
None
return
self
.
course
.
get_clients_filtered
(
groups_entities
,
roles_entities
)
return
self
.
course
.
get_clients_filtered
(
groups_entities
,
roles_entities
,
client_type
=
client_type
)
tests/database/test_db.py
View file @
c0a95638
...
...
@@ -869,6 +869,7 @@ def test_user_roles_for_course(session):
assert
len
(
cpp_roles
)
==
2
assert
teacher_cpp
in
cpp_roles
assert
lect_cpp
in
cpp_roles
assert
len
(
course
.
get_clients_filtered
(
client_type
=
ClientType
.
USER
))
==
1
java_roles
=
user
.
get_roles_in_course
(
course
=
c_java
)
assert
len
(
java_roles
)
==
1
...
...
tests/rest/test_course.py
View file @
c0a95638
...
...
@@ -79,19 +79,37 @@ def test_read(client):
rest_tools
.
assert_course
(
c
,
course
)
def
test_read_course_
user
s
(
client
):
def
test_read_course_
client
s
(
client
):
course
=
Course
.
query
.
filter_by
(
codename
=
"testcourse2"
).
first
()
response
=
rest_tools
.
make_request
(
client
,
f
"/courses/
{
course
.
id
}
/clients"
)
assert_response
(
response
,
200
)
users
=
rest_tools
.
extract_data
(
response
)
course_users
=
set
()
for
role
in
course
.
roles
:
course_users
.
update
(
role
.
clients
)
course_users
.
update
(
[
c
.
id
for
c
in
role
.
clients
]
)
assert
users
assert
len
(
users
)
==
4
assert
len
(
users
)
==
5
assert
len
(
course_users
)
==
len
(
users
)
def
test_read_course_client_type_workers
(
client
):
course
=
Course
.
query
.
filter_by
(
codename
=
"testcourse1"
).
first
()
response
=
rest_tools
.
make_request
(
client
,
f
"/courses/
{
course
.
id
}
/clients?type=worker"
)
assert_response
(
response
,
200
)
workers
=
rest_tools
.
extract_data
(
response
)
assert
workers
assert
len
(
workers
)
==
1
def
test_read_course_client_type_users
(
rest_service
,
client
):
course
=
Course
.
query
.
filter_by
(
codename
=
"testcourse1"
).
first
()
response
=
rest_tools
.
make_request
(
client
,
f
"/courses/
{
course
.
id
}
/clients?type=user"
)
assert_response
(
response
,
200
)
users
=
rest_tools
.
extract_data
(
response
)
assert
users
assert
len
(
users
)
==
5
def
test_update
(
client
):
c
=
Course
.
query
.
filter_by
(
codename
=
"testcourse1"
).
first
()
request_dict
=
dict
(
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment