Merge branch 'hotfix/remove-private-user-node' into develop

This commit is contained in:
Ramon Wenger 2024-03-28 15:41:10 +01:00
commit 5dca389003
4 changed files with 272 additions and 270 deletions

View File

@ -262,7 +262,7 @@ export type AnswerNode = Node & {
data: Scalars['JSONString']['output'];
/** The ID of the object */
id: Scalars['ID']['output'];
owner: PrivateUserNode;
owner: PublicUserNode;
pk?: Maybe<Scalars['Int']['output']>;
survey: SurveyNode;
};
@ -313,7 +313,7 @@ export type AssignmentNode = Node & {
id: Scalars['ID']['output'];
modified: Scalars['DateTime']['output'];
module: ModuleNode;
owner?: Maybe<PrivateUserNode>;
owner?: Maybe<PublicUserNode>;
path: Scalars['String']['output'];
solution?: Maybe<Scalars['String']['output']>;
submission?: Maybe<StudentSubmissionNode>;
@ -349,7 +349,7 @@ export type ChapterBookmarkNode = Node & {
id: Scalars['ID']['output'];
note?: Maybe<NoteNode>;
path?: Maybe<Scalars['String']['output']>;
user: PrivateUserNode;
user: PublicUserNode;
};
export type ChapterBookmarkNodeConnection = {
@ -439,7 +439,7 @@ export type ContentBlockBookmarkNode = Node & {
id: Scalars['ID']['output'];
note?: Maybe<NoteNode>;
path?: Maybe<Scalars['String']['output']>;
user: PrivateUserNode;
user: PublicUserNode;
uuid?: Maybe<Scalars['UUID']['output']>;
};
@ -770,7 +770,7 @@ export type HighlightNode = Node & {
selectionLength: Scalars['Int']['output'];
startPosition: Scalars['Int']['output'];
text: Scalars['String']['output'];
user: PrivateUserNode;
user: PublicUserNode;
};
export type HighlightableNode = ChapterNode | ContentBlockNode | InstrumentNode | ModuleNode;
@ -796,7 +796,7 @@ export type InstrumentBookmarkNode = Node & {
instrument: InstrumentNode;
note?: Maybe<NoteNode>;
path: Scalars['String']['output'];
user: PrivateUserNode;
user: PublicUserNode;
uuid?: Maybe<Scalars['UUID']['output']>;
};
@ -899,7 +899,7 @@ export type ModuleBookmarkNode = {
module: ModuleNode;
note?: Maybe<NoteNode>;
path?: Maybe<Scalars['String']['output']>;
user: PrivateUserNode;
user: PublicUserNode;
};
export type ModuleCategoryNode = Node & {
@ -1519,7 +1519,7 @@ export type ObjectiveNode = Node & {
id: Scalars['ID']['output'];
mine?: Maybe<Scalars['Boolean']['output']>;
order?: Maybe<Scalars['Int']['output']>;
owner?: Maybe<PrivateUserNode>;
owner?: Maybe<PublicUserNode>;
pk?: Maybe<Scalars['Int']['output']>;
text: Scalars['String']['output'];
userCreated?: Maybe<Scalars['Boolean']['output']>;
@ -1655,11 +1655,10 @@ export type ProjectNode = Node & {
/** The ID of the object */
id: Scalars['ID']['output'];
objectives: Scalars['String']['output'];
owner?: Maybe<PublicUserNode>;
pk?: Maybe<Scalars['Int']['output']>;
schoolClass?: Maybe<SchoolClassNode>;
slug: Scalars['String']['output'];
student: PrivateUserNode;
student?: Maybe<PublicUserNode>;
title: Scalars['String']['output'];
};
@ -2125,7 +2124,7 @@ export type StudentSubmissionNode = Node & {
/** The ID of the object */
id: Scalars['ID']['output'];
modified: Scalars['DateTime']['output'];
student: PrivateUserNode;
student: PublicUserNode;
submissionFeedback?: Maybe<SubmissionFeedbackNode>;
text: Scalars['String']['output'];
};
@ -2145,7 +2144,7 @@ export type SubmissionFeedbackNode = Node & {
id: Scalars['ID']['output'];
modified: Scalars['DateTime']['output'];
studentSubmission: StudentSubmissionNode;
teacher: PrivateUserNode;
teacher: PublicUserNode;
text: Scalars['String']['output'];
};
@ -2213,7 +2212,7 @@ export type SyncModuleVisibilityPayload = {
export type TeamNode = Node & {
__typename?: 'TeamNode';
code?: Maybe<Scalars['String']['output']>;
creator?: Maybe<PrivateUserNode>;
creator: PublicUserNode;
/** The ID of the object */
id: Scalars['ID']['output'];
isDeleted: Scalars['Boolean']['output'];
@ -2695,7 +2694,7 @@ export type ReadOnlyQueryQueryVariables = Exact<{ [key: string]: never; }>;
export type ReadOnlyQueryQuery = { __typename?: 'Query', me?: { __typename?: 'PrivateUserNode', readOnly?: boolean | null, selectedClass?: { __typename?: 'SchoolClassNode', readOnly?: boolean | null } | null } | null };
export type SubmissionPartsFragment = { __typename?: 'StudentSubmissionNode', id: string, text: string, final: boolean, document: string, submissionFeedback?: { __typename?: 'SubmissionFeedbackNode', id: string, text: string, teacher: { __typename?: 'PrivateUserNode', firstName: string, lastName: string } } | null } & { ' $fragmentName'?: 'SubmissionPartsFragment' };
export type SubmissionPartsFragment = { __typename?: 'StudentSubmissionNode', id: string, text: string, final: boolean, document: string, submissionFeedback?: { __typename?: 'SubmissionFeedbackNode', id: string, text: string, teacher: { __typename?: 'PublicUserNode', firstName: string, lastName: string } } | null } & { ' $fragmentName'?: 'SubmissionPartsFragment' };
export type AssignmentPartsFragment = { __typename?: 'AssignmentNode', id: string, title: string, assignment: string, solution?: string | null, submission?: (
{ __typename?: 'StudentSubmissionNode' }

View File

@ -5,7 +5,7 @@ from graphene_django import DjangoObjectType
from api.utils import get_by_id_or_slug
from portfolio.models import Project, ProjectEntry
from users.models import Role, UserRole, User
from users.models import Role, UserRole
from users.schema import PublicUserNode
@ -13,18 +13,18 @@ class ProjectEntryNode(DjangoObjectType):
class Meta:
model = ProjectEntry
interfaces = (relay.Node,)
fields = ('description', 'document_url', 'project', 'created')
fields = ("description", "document_url", "project", "created")
class ProjectNode(DjangoObjectType):
pk = graphene.Int()
entries_count = graphene.Int()
entries = graphene.List(ProjectEntryNode)
owner = graphene.Field(PublicUserNode)
student = graphene.Field(PublicUserNode)
class Meta:
model = Project
filter_fields = ['slug', 'appearance']
filter_fields = ["slug", "appearance"]
interfaces = (relay.Node,)
def resolve_pk(self, *args, **kwargs):
@ -45,11 +45,16 @@ class PortfolioQuery(object):
def resolve_projects(self, info, **kwargs):
user = info.context.user
if user.is_superuser:
return Project.objects.all().order_by('-pk')
return Project.objects.all().order_by("-pk")
if UserRole.get_role_for_user(user).role == Role.objects.get_default_teacher_role():
return Project.objects.filter(Q(student__school_classes__in=user.school_classes.all(), final=True) |
Q(student=user, final=False)).distinct()
if (
UserRole.get_role_for_user(user).role
== Role.objects.get_default_teacher_role()
):
return Project.objects.filter(
Q(student__school_classes__in=user.school_classes.all(), final=True)
| Q(student=user, final=False)
).distinct()
return Project.objects.filter(student=user)

View File

@ -170,7 +170,7 @@ type TopicNode implements Node {
type HighlightNode implements Node {
"""The ID of the object"""
id: ID!
user: PrivateUserNode!
user: PublicUserNode!
page: HighlightableNode!
contentIndex: Int
contentUuid: UUID
@ -182,45 +182,195 @@ type HighlightNode implements Node {
color: String!
}
type PrivateUserNode implements Node {
type PublicUserNode implements Node {
firstName: String!
lastName: String!
avatarUrl: String!
"""The ID of the object"""
id: ID!
fullName: String!
isMe: Boolean
}
union HighlightableNode = ContentBlockNode | InstrumentNode | ModuleNode | ChapterNode
type ContentBlockNode implements Node & ContentBlockInterface {
title: String
"""
Erforderlich. 150 Zeichen oder weniger. Nur Buchstaben, Ziffern und @/./+/-/_.
Der Name der Seite, wie er in URLs angezeigt werden soll, z.B. http://domain.com/blog/[my-slug]/
"""
username: String!
lastModule: ModuleNode
lastModuleLevel: ModuleLevelNode
lastTopic: TopicNode
email: String!
onboardingVisited: Boolean!
team: TeamNode
schoolClasses: [SchoolClassNode]
slug: String!
hiddenFor: [SchoolClassNode]
visibleFor: [SchoolClassNode]
userCreated: Boolean!
contents: GenericStreamFieldType
type: String!
"""The ID of the object"""
id: ID!
mine: Boolean
bookmarks: [ContentBlockBookmarkNode]
originalCreator: PublicUserNode
instrumentCategory: InstrumentCategoryNode
path: String
highlights: [HighlightNode]
}
interface ContentBlockInterface {
title: String
contents: GenericStreamFieldType
type: String!
}
scalar GenericStreamFieldType
type SchoolClassNode implements Node {
name: String!
code: String
"""The ID of the object"""
id: ID!
pk: Int
permissions: [String]
selectedClass: SchoolClassNode
expiryDate: String
isTeacher: Boolean
oldClasses: [SchoolClassNode]
recentModules(
offset: Int
before: String
after: String
first: Int
last: Int
recentModules: ID
"""Sortierung"""
orderBy: String
): ModuleNodeConnection
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!
user: PublicUserNode!
note: NoteNode
uuid: UUID
contentBlock: ContentBlockNode!
path: String
content: String
}
type NoteNode implements Node {
"""The ID of the object"""
id: ID!
text: String!
contentblockbookmark: ContentBlockBookmarkNode
modulebookmark: ModuleBookmarkNode
chapterbookmark: ChapterBookmarkNode
instrumentbookmark: InstrumentBookmarkNode
highlight: HighlightNode
pk: Int
}
type ModuleBookmarkNode {
id: ID!
user: PublicUserNode!
note: NoteNode
module: ModuleNode!
path: String
content: String
}
type ChapterBookmarkNode implements Node {
"""The ID of the object"""
id: ID!
user: PublicUserNode!
note: NoteNode
chapter: ChapterNode!
path: String
content: String
}
type ChapterNode implements Node & ChapterInterface {
title: String
"""
Der Name der Seite, wie er in URLs angezeigt werden soll, z.B. http://domain.com/blog/[my-slug]/
"""
slug: String!
description: String
titleHiddenFor: [SchoolClassNode]
descriptionHiddenFor: [SchoolClassNode]
"""The ID of the object"""
id: ID!
bookmark: ChapterBookmarkNode
contentBlocks: [ContentBlockNode]
path: String
highlights: [HighlightNode]
}
interface ChapterInterface {
description: String
title: String
}
type InstrumentBookmarkNode implements Node {
"""The ID of the object"""
id: ID!
user: PublicUserNode!
note: NoteNode
uuid: UUID
instrument: InstrumentNode!
path: String!
content: String
}
"""
Leverages the internal Python implementation of UUID (uuid.UUID) to provide native UUID objects
in fields, resolvers and input.
"""
scalar UUID
type InstrumentNode implements Node {
"""Der Seitentitel, der öffentlich angezeigt werden soll"""
title: String!
"""
Der Name der Seite, wie er in URLs angezeigt werden soll, z.B. http://domain.com/blog/[my-slug]/
"""
slug: String!
intro: String!
contents: GenericStreamFieldType
"""The ID of the object"""
id: ID!
bookmarks: [InstrumentBookmarkNode]
type: InstrumentTypeNode
language: String
highlights: [HighlightNode!]!
path: String!
}
type InstrumentTypeNode implements Node {
"""The ID of the object"""
id: ID!
name: String!
category: InstrumentCategoryNode
type: String!
}
type InstrumentCategoryNode implements Node {
"""The ID of the object"""
id: ID!
name: String!
background: String!
foreground: String!
types: [InstrumentTypeNode]
}
type ModuleLevelNode implements Node {
"""The ID of the object"""
id: ID!
@ -275,206 +425,6 @@ type ModuleNodeEdge {
cursor: String!
}
type TeamNode implements Node {
"""The ID of the object"""
id: ID!
name: String!
isDeleted: Boolean!
code: String
creator: PrivateUserNode
members: [PublicUserNode]
pk: Int
}
type PublicUserNode implements Node {
firstName: String!
lastName: String!
avatarUrl: String!
"""The ID of the object"""
id: ID!
fullName: String!
isMe: Boolean
}
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
type ContentBlockNode implements Node & ContentBlockInterface {
title: String
"""
Der Name der Seite, wie er in URLs angezeigt werden soll, z.B. http://domain.com/blog/[my-slug]/
"""
slug: String!
hiddenFor: [SchoolClassNode]
visibleFor: [SchoolClassNode]
userCreated: Boolean!
contents: GenericStreamFieldType
type: String!
"""The ID of the object"""
id: ID!
mine: Boolean
bookmarks: [ContentBlockBookmarkNode]
originalCreator: PublicUserNode
instrumentCategory: InstrumentCategoryNode
path: String
highlights: [HighlightNode]
}
interface ContentBlockInterface {
title: String
contents: GenericStreamFieldType
type: String!
}
scalar GenericStreamFieldType
type ContentBlockBookmarkNode implements Node {
"""The ID of the object"""
id: ID!
user: PrivateUserNode!
note: NoteNode
uuid: UUID
contentBlock: ContentBlockNode!
path: String
content: String
}
type NoteNode implements Node {
"""The ID of the object"""
id: ID!
text: String!
contentblockbookmark: ContentBlockBookmarkNode
modulebookmark: ModuleBookmarkNode
chapterbookmark: ChapterBookmarkNode
instrumentbookmark: InstrumentBookmarkNode
highlight: HighlightNode
pk: Int
}
type ModuleBookmarkNode {
id: ID!
user: PrivateUserNode!
note: NoteNode
module: ModuleNode!
path: String
content: String
}
type ChapterBookmarkNode implements Node {
"""The ID of the object"""
id: ID!
user: PrivateUserNode!
note: NoteNode
chapter: ChapterNode!
path: String
content: String
}
type ChapterNode implements Node & ChapterInterface {
title: String
"""
Der Name der Seite, wie er in URLs angezeigt werden soll, z.B. http://domain.com/blog/[my-slug]/
"""
slug: String!
description: String
titleHiddenFor: [SchoolClassNode]
descriptionHiddenFor: [SchoolClassNode]
"""The ID of the object"""
id: ID!
bookmark: ChapterBookmarkNode
contentBlocks: [ContentBlockNode]
path: String
highlights: [HighlightNode]
}
interface ChapterInterface {
description: String
title: String
}
type InstrumentBookmarkNode implements Node {
"""The ID of the object"""
id: ID!
user: PrivateUserNode!
note: NoteNode
uuid: UUID
instrument: InstrumentNode!
path: String!
content: String
}
"""
Leverages the internal Python implementation of UUID (uuid.UUID) to provide native UUID objects
in fields, resolvers and input.
"""
scalar UUID
type InstrumentNode implements Node {
"""Der Seitentitel, der öffentlich angezeigt werden soll"""
title: String!
"""
Der Name der Seite, wie er in URLs angezeigt werden soll, z.B. http://domain.com/blog/[my-slug]/
"""
slug: String!
intro: String!
contents: GenericStreamFieldType
"""The ID of the object"""
id: ID!
bookmarks: [InstrumentBookmarkNode]
type: InstrumentTypeNode
language: String
highlights: [HighlightNode!]!
path: String!
}
type InstrumentTypeNode implements Node {
"""The ID of the object"""
id: ID!
name: String!
category: InstrumentCategoryNode
type: String!
}
type InstrumentCategoryNode implements Node {
"""The ID of the object"""
id: ID!
name: String!
background: String!
foreground: String!
types: [InstrumentTypeNode]
}
type ModuleCategoryNode implements Node {
"""The ID of the object"""
id: ID!
@ -504,7 +454,7 @@ type AssignmentNode implements Node {
assignment: String!
solution: String
deleted: Boolean!
owner: PrivateUserNode
owner: PublicUserNode
module: ModuleNode!
userCreated: Boolean!
taskbaseId: String
@ -528,7 +478,7 @@ type StudentSubmissionNode implements Node {
text: String!
document: String!
assignment: AssignmentNode!
student: PrivateUserNode!
student: PublicUserNode!
final: Boolean!
submissionFeedback: SubmissionFeedbackNode
}
@ -537,7 +487,7 @@ type SubmissionFeedbackNode implements Node {
created: DateTime!
modified: DateTime!
text: String!
teacher: PrivateUserNode!
teacher: PublicUserNode!
studentSubmission: StudentSubmissionNode!
final: Boolean!
@ -573,7 +523,7 @@ type ObjectiveNode implements Node {
id: ID!
text: String!
group: ObjectiveGroupNode!
owner: PrivateUserNode
owner: PublicUserNode
hiddenFor: [SchoolClassNode]
visibleFor: [SchoolClassNode]
order: Int
@ -697,7 +647,7 @@ type SnapshotChangesNode {
type AnswerNode implements Node {
"""The ID of the object"""
id: ID!
owner: PrivateUserNode!
owner: PublicUserNode!
data: JSONString!
survey: SurveyNode!
pk: Int
@ -789,13 +739,12 @@ type ProjectNode implements Node {
slug: String!
objectives: String!
appearance: String!
student: PrivateUserNode!
student: PublicUserNode
final: Boolean!
schoolClass: SchoolClassNode
entries: [ProjectEntryNode]
pk: Int
entriesCount: Int
owner: PublicUserNode
}
type ProjectEntryNode implements Node {
@ -940,6 +889,55 @@ type CommentNode implements Node {
id: ID!
}
type PrivateUserNode implements Node {
"""
Erforderlich. 150 Zeichen oder weniger. Nur Buchstaben, Ziffern und @/./+/-/_.
"""
username: String!
firstName: String!
lastName: String!
lastModule: ModuleNode
lastModuleLevel: ModuleLevelNode
lastTopic: TopicNode
avatarUrl: String!
email: String!
onboardingVisited: Boolean!
team: TeamNode
schoolClasses: [SchoolClassNode]
"""The ID of the object"""
id: ID!
pk: Int
permissions: [String]
selectedClass: SchoolClassNode
expiryDate: String
isTeacher: Boolean
oldClasses: [SchoolClassNode]
recentModules(
offset: Int
before: String
after: String
first: Int
last: Int
recentModules: ID
"""Sortierung"""
orderBy: String
): ModuleNodeConnection
readOnly: Boolean
}
type TeamNode implements Node {
"""The ID of the object"""
id: ID!
name: String!
isDeleted: Boolean!
code: String
creator: PublicUserNode
members: [PublicUserNode]
pk: Int
}
type PrivateUserNodeConnection {
"""Pagination data for this connection."""
pageInfo: PageInfo!

View File

@ -70,20 +70,6 @@ class TeamNode(DjangoObjectType):
return self.members.all()
class PublicUserNode(DjangoObjectType):
full_name = graphene.String(required=True)
is_me = graphene.Boolean()
class Meta:
model = User
only_fields = ["full_name", "first_name", "last_name", "avatar_url"]
interfaces = (relay.Node,)
@staticmethod
def resolve_is_me(parent: User, info, **kwargs):
return info.context.user.pk == parent.pk
class PrivateUserNode(DjangoObjectType):
class Meta:
model = User
@ -168,6 +154,20 @@ class PrivateUserNode(DjangoObjectType):
return self.team
class PublicUserNode(DjangoObjectType):
full_name = graphene.String(required=True)
is_me = graphene.Boolean()
class Meta:
model = User
only_fields = ["full_name", "first_name", "last_name", "avatar_url"]
interfaces = (relay.Node,)
@staticmethod
def resolve_is_me(parent: User, info, **kwargs):
return info.context.user.pk == parent.pk
class ClassMemberNode(ObjectType):
"""
We need to build this ourselves, because we want the active property on the node, because providing it on the