Fix project page schema

This commit is contained in:
Ramon Wenger 2024-03-28 16:12:48 +01:00
parent 5dca389003
commit 98771b2db2
5 changed files with 76 additions and 51 deletions

View File

@ -1671,6 +1671,7 @@ export type PublicUserNode = Node & {
id: Scalars['ID']['output'];
isMe?: Maybe<Scalars['Boolean']['output']>;
lastName: Scalars['String']['output'];
schoolClasses?: Maybe<Array<Maybe<SchoolClassNode>>>;
};
export type Query = {
@ -2212,7 +2213,7 @@ export type SyncModuleVisibilityPayload = {
export type TeamNode = Node & {
__typename?: 'TeamNode';
code?: Maybe<Scalars['String']['output']>;
creator: PublicUserNode;
creator?: Maybe<PublicUserNode>;
/** The ID of the object */
id: Scalars['ID']['output'];
isDeleted: Scalars['Boolean']['output'];

View File

@ -15,6 +15,7 @@
:final="project.final"
data-cy="project-share-link"
class="project__share"
v-if="canEdit"
@share="updateProjectShareState(project.slug, !project.final)"
/>
@ -109,7 +110,9 @@ export default {
return [cls ? `project--${cls}` : ''];
},
isOwner() {
return this.me.id === this.project.student.id;
const myId = window.atob(this.me.id).split(':')[1];
const projectId = window.atob(this.project.student.id).split(':')[1];
return myId === projectId;
},
projectEntryCount() {
return this.project.entries ? this.project.entries.length : 0;

View File

@ -17,14 +17,16 @@ query ProjectQuery($id: ID!) {
class ProjectQueryTestCase(SkillboxTestCase):
def _test_direct_project_access(self, user: User, should_have_access: bool):
result = self.get_client(user).execute(project_query, variables={
'id': self.project1.graphql_id
})
result = self.get_client(user).execute(
project_query, variables={"id": self.project1.graphql_id}
)
self.assertIsNone(result.errors)
if should_have_access:
self.assertEqual(result.data.get('project').get('id'), self.project1.graphql_id)
self.assertEqual(
result.data.get("project").get("id"), self.project1.graphql_id
)
else:
self.assertIsNone(result.data.get('project'))
self.assertIsNone(result.data.get("project"))
def setUp(self):
self.createDefault()
@ -32,8 +34,8 @@ class ProjectQueryTestCase(SkillboxTestCase):
school_class2 = SchoolClassFactory(users=[self.teacher2, self.student2])
self.project1 = ProjectFactory(student=self.student1)
self.project1_id = to_global_id('ProjectNode', self.project1.id)
self.query = '''
self.project1_id = to_global_id("ProjectNode", self.project1.id)
self.query = """
query ProjectsQuery {
projects {
...ProjectParts
@ -50,7 +52,7 @@ class ProjectQueryTestCase(SkillboxTestCase):
__typename
}
'''
"""
def test_should_see_own_projects(self):
self.assertEqual(Project.objects.count(), 1)
@ -58,7 +60,9 @@ class ProjectQueryTestCase(SkillboxTestCase):
result = self.get_client(self.student1).execute(self.query)
self.assertIsNone(result.errors)
self.assertEqual(result.data.get('projects')[0].get('title'), self.project1.title)
self.assertEqual(
result.data.get("projects")[0].get("title"), self.project1.title
)
def test_should_not_see_other_projects(self):
self.assertEqual(Project.objects.count(), 1)
@ -66,13 +70,13 @@ class ProjectQueryTestCase(SkillboxTestCase):
result = self.get_client(self.student2).execute(self.query)
self.assertIsNone(result.errors)
self.assertEqual(len(result.data.get('projects')), 0)
self.assertEqual(len(result.data.get("projects")), 0)
def test_teacher_should_not_see_unfinished_projects(self):
result = self.get_client().execute(self.query)
self.assertIsNone(result.errors)
self.assertEqual(len(result.data.get('projects')), 0)
self.assertEqual(len(result.data.get("projects")), 0)
def test_teacher_should_only_see_finished_projects(self):
self.project1.final = True
@ -82,8 +86,9 @@ class ProjectQueryTestCase(SkillboxTestCase):
result = self.get_client().execute(self.query)
self.assertIsNone(result.errors)
self.assertEqual(result.data.get('projects')[0].get('title'),
self.project1.title)
self.assertEqual(
result.data.get("projects")[0].get("title"), self.project1.title
)
def test_other_teacher_should_not_see_projects(self):
self.project1.final = True
@ -93,11 +98,13 @@ class ProjectQueryTestCase(SkillboxTestCase):
result = self.get_client(self.teacher2).execute(self.query)
self.assertIsNone(result.errors)
self.assertEqual(len(result.data.get('projects')), 0)
self.assertEqual(len(result.data.get("projects")), 0)
def test_class_with_two_teachers_both_can_see_project(self):
# create class with two teachers
school_class3 = SchoolClassFactory(users=[self.teacher, self.teacher2, self.student1])
school_class3 = SchoolClassFactory(
users=[self.teacher, self.teacher2, self.student1]
)
self.project1.final = True
self.project1.save()
@ -105,16 +112,18 @@ class ProjectQueryTestCase(SkillboxTestCase):
# teacher can see project
result = self.get_client(self.teacher).execute(self.query)
self.assertIsNone(result.errors)
self.assertEqual(len(result.data.get('projects')), 1)
self.assertEqual(len(result.data.get("projects")), 1)
# teacher2 can see project
result = self.get_client(self.teacher2).execute(self.query)
self.assertIsNone(result.errors)
self.assertEqual(len(result.data.get('projects')), 1)
self.assertEqual(len(result.data.get("projects")), 1)
def test_class_with_two_teachers_direct_final_project_access(self):
# create class with two teachers
school_class3 = SchoolClassFactory(users=[self.teacher, self.teacher2, self.student1])
school_class3 = SchoolClassFactory(
users=[self.teacher, self.teacher2, self.student1]
)
self.project1.final = True
self.project1.save()
@ -136,7 +145,6 @@ class ProjectQueryTestCase(SkillboxTestCase):
# non-owner can't access project
self._test_direct_project_access(self.student2, False)
def test_direct_final_project_access(self):
self.project1.final = True
self.project1.save()
@ -155,12 +163,14 @@ query ProjectQuery($id: ID!) {
project(id: $id) {
id
student {
email
fullName
}
}
}
"""
result = self.get_client(self.student1).execute(query, variables={
'id': self.project1.graphql_id
})
self.assertEqual(result.data['project']['student']['email'], self.student1.email)
result = self.get_client(self.student1).execute(
query, variables={"id": self.project1.graphql_id}
)
self.assertEqual(
result.data["project"]["student"]["fullName"], self.student1.full_name
)

View File

@ -191,6 +191,32 @@ type PublicUserNode implements Node {
id: ID!
fullName: String!
isMe: Boolean
schoolClasses: [SchoolClassNode]
}
type SchoolClassNode implements Node {
name: String!
code: String
"""The ID of the object"""
id: ID!
pk: Int
members: [ClassMemberNode]
readOnly: Boolean
}
"""
We need to build this ourselves, because we want the active property on the node, because providing it on the
Connection or Edge for a UserNodeConnection is difficult.
"""
type ClassMemberNode {
user: PublicUserNode
active: Boolean
firstName: String
lastName: String
isTeacher: Boolean
id: ID
isMe: Boolean
}
union HighlightableNode = ContentBlockNode | InstrumentNode | ModuleNode | ChapterNode
@ -226,31 +252,6 @@ interface ContentBlockInterface {
scalar GenericStreamFieldType
type SchoolClassNode implements Node {
name: String!
code: String
"""The ID of the object"""
id: ID!
pk: Int
members: [ClassMemberNode]
readOnly: Boolean
}
"""
We need to build this ourselves, because we want the active property on the node, because providing it on the
Connection or Edge for a UserNodeConnection is difficult.
"""
type ClassMemberNode {
user: PublicUserNode
active: Boolean
firstName: String
lastName: String
isTeacher: Boolean
id: ID
isMe: Boolean
}
type ContentBlockBookmarkNode implements Node {
"""The ID of the object"""
id: ID!

View File

@ -157,6 +157,7 @@ class PrivateUserNode(DjangoObjectType):
class PublicUserNode(DjangoObjectType):
full_name = graphene.String(required=True)
is_me = graphene.Boolean()
school_classes = graphene.List(SchoolClassNode)
class Meta:
model = User
@ -167,6 +168,15 @@ class PublicUserNode(DjangoObjectType):
def resolve_is_me(parent: User, info, **kwargs):
return info.context.user.pk == parent.pk
@staticmethod
def resolve_school_classes(root: User, info):
if root.selected_class is None: # then we don't have any class to return
return SchoolClass.objects.none()
return SchoolClass.objects.filter(
Q(schoolclassmember__active=True, schoolclassmember__user=root)
| Q(pk=root.selected_class.pk)
).distinct()
class ClassMemberNode(ObjectType):
"""