Merge branch 'hotfix/srf-new-embed-link' into develop
This commit is contained in:
commit
c0e93f666d
|
|
@ -18,7 +18,7 @@ const documents = {
|
||||||
"\n fragment ContentBlockHighlightsFragment on ContentBlockNode {\n id\n __typename\n highlights {\n ...HighlightParts\n }\n }\n": types.ContentBlockHighlightsFragmentFragmentDoc,
|
"\n fragment ContentBlockHighlightsFragment on ContentBlockNode {\n id\n __typename\n highlights {\n ...HighlightParts\n }\n }\n": types.ContentBlockHighlightsFragmentFragmentDoc,
|
||||||
"\n query LanguageQuery {\n me {\n language @client\n }\n }\n ": types.LanguageQueryDocument,
|
"\n query LanguageQuery {\n me {\n language @client\n }\n }\n ": types.LanguageQueryDocument,
|
||||||
"\n mutation SetLanguage($language: String!) {\n setLanguage(language: $language) @client {\n language\n }\n }\n ": types.SetLanguageDocument,
|
"\n mutation SetLanguage($language: String!) {\n setLanguage(language: $language) @client {\n language\n }\n }\n ": types.SetLanguageDocument,
|
||||||
"\n query ReadOnlyQuery {\n me {\n readOnly\n selectedClass {\n readOnly\n }\n }\n }\n": types.ReadOnlyQueryDocument,
|
"\n query ReadOnlyQuery {\n me {\n readOnly\n selectedClass {\n readOnly\n }\n }\n }\n ": types.ReadOnlyQueryDocument,
|
||||||
"\n fragment SubmissionParts on StudentSubmissionNode {\n id\n text\n final\n document\n submissionFeedback {\n id\n text\n teacher {\n firstName\n lastName\n }\n }\n }\n": types.SubmissionPartsFragmentDoc,
|
"\n fragment SubmissionParts on StudentSubmissionNode {\n id\n text\n final\n document\n submissionFeedback {\n id\n text\n teacher {\n firstName\n lastName\n }\n }\n }\n": types.SubmissionPartsFragmentDoc,
|
||||||
"\n fragment AssignmentParts on AssignmentNode {\n id\n title\n assignment\n solution\n submission {\n ...SubmissionParts\n }\n }\n": types.AssignmentPartsFragmentDoc,
|
"\n fragment AssignmentParts on AssignmentNode {\n id\n title\n assignment\n solution\n submission {\n ...SubmissionParts\n }\n }\n": types.AssignmentPartsFragmentDoc,
|
||||||
"\n query AssignmentQuery($id: ID!) {\n assignment(id: $id) {\n ...AssignmentParts\n }\n }\n ": types.AssignmentQueryDocument,
|
"\n query AssignmentQuery($id: ID!) {\n assignment(id: $id) {\n ...AssignmentParts\n }\n }\n ": types.AssignmentQueryDocument,
|
||||||
|
|
@ -97,7 +97,7 @@ export function graphql(source: "\n mutation SetLanguage($language: String!)
|
||||||
/**
|
/**
|
||||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||||
*/
|
*/
|
||||||
export function graphql(source: "\n query ReadOnlyQuery {\n me {\n readOnly\n selectedClass {\n readOnly\n }\n }\n }\n"): (typeof documents)["\n query ReadOnlyQuery {\n me {\n readOnly\n selectedClass {\n readOnly\n }\n }\n }\n"];
|
export function graphql(source: "\n query ReadOnlyQuery {\n me {\n readOnly\n selectedClass {\n readOnly\n }\n }\n }\n "): (typeof documents)["\n query ReadOnlyQuery {\n me {\n readOnly\n selectedClass {\n readOnly\n }\n }\n }\n "];
|
||||||
/**
|
/**
|
||||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -26,49 +26,60 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script>
|
||||||
import { graphql } from '@/__generated__';
|
import gql from 'graphql-tag';
|
||||||
import { LICENSE_ACTIVATION } from '@/router/auth.names';
|
import { LICENSE_ACTIVATION } from '@/router/auth.names';
|
||||||
import { useQuery } from '@vue/apollo-composable';
|
|
||||||
import { computed } from 'vue';
|
|
||||||
|
|
||||||
const query = graphql(`
|
export default {
|
||||||
query ReadOnlyQuery {
|
data() {
|
||||||
me {
|
return {
|
||||||
readOnly
|
me: {
|
||||||
selectedClass {
|
|
||||||
readOnly
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`);
|
|
||||||
|
|
||||||
const { result } = useQuery(query, null, {
|
|
||||||
fetchPolicy: 'cache-only',
|
|
||||||
});
|
|
||||||
|
|
||||||
const me = computed(() => {
|
|
||||||
const me = result.value?.me;
|
|
||||||
return (
|
|
||||||
me || {
|
|
||||||
readOnly: false,
|
|
||||||
selectedClass: {
|
|
||||||
readOnly: false,
|
readOnly: false,
|
||||||
|
selectedClass: {
|
||||||
|
readOnly: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
licenseActivationLink: {
|
||||||
);
|
name: LICENSE_ACTIVATION,
|
||||||
});
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
const isReadOnly = computed(() => {
|
apollo: {
|
||||||
return me.value.readOnly || me.value.selectedClass?.readOnly;
|
me: {
|
||||||
});
|
query: gql`
|
||||||
|
query ReadOnlyQuery {
|
||||||
|
me {
|
||||||
|
readOnly
|
||||||
|
selectedClass {
|
||||||
|
readOnly
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
fetchPolicy: 'cache-only',
|
||||||
|
update({ me }) {
|
||||||
|
if (!me) {
|
||||||
|
return {
|
||||||
|
readOnly: false,
|
||||||
|
selectedClass: {
|
||||||
|
readOnly: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return me;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
const readOnlyText = computed(() => {
|
computed: {
|
||||||
return me.value.readOnly ? 'Sie besitzen keine aktive Lizenz.' : 'Sie sind in dieser Klasse nicht mehr aktiv.';
|
readOnlyText() {
|
||||||
});
|
return this.me.readOnly ? 'Sie besitzen keine aktive Lizenz.' : 'Sie sind in dieser Klasse nicht mehr aktiv.';
|
||||||
|
},
|
||||||
const licenseActivationLink = {
|
isReadOnly() {
|
||||||
name: LICENSE_ACTIVATION,
|
return this.me.readOnly || this.me.selectedClass?.readOnly;
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,6 @@ const typePolicies = {
|
||||||
keyFields: ['slug'],
|
keyFields: ['slug'],
|
||||||
},
|
},
|
||||||
PrivateUserNode: {
|
PrivateUserNode: {
|
||||||
keyFields: [], // i should never see anyone else's PrivateUserNode, so this should be a singleton
|
|
||||||
fields: {
|
fields: {
|
||||||
language: {
|
language: {
|
||||||
read() {
|
read() {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,12 @@
|
||||||
const YOUTUBE = /^(?:https:\/\/)?(?:www.)?(?:youtube.com\/watch\?v=|youtu.be\/)([a-zA-Z0-9_-]{11})(?:.+)?$/;
|
const YOUTUBE = /^(?:https:\/\/)?(?:www.)?(?:youtube.com\/watch\?v=|youtu.be\/)([a-zA-Z0-9_-]{11})(?:.+)?$/;
|
||||||
const VIMEO = /^(?:https:\/\/)?(?:www.)?vimeo.com\/([a-zA-Z0-9]*)$/;
|
const VIMEO = /^(?:https:\/\/)?(?:www.)?vimeo.com\/([a-zA-Z0-9]*)$/;
|
||||||
// const SRF = /^(?:https:\/\/)?(?:www.)?srf.ch\/(?:[\w/-]*)[?&]id=([\w-]+)(?:[&\w=-]*)$/;
|
/*
|
||||||
const SRF = /^(?:https:\/\/)?(?:www.)?srf.ch\/(?:[\w/-]*)[?&]id=([\w-]+)(?:[&\w=-]*)(?:&?startTime=([\d.]+))?/;
|
* Handles URLs like
|
||||||
|
* - https://www.srf.ch/play/tv/popupvideoplayer?id=6db02b8b-975c-4e3e-8260-f1e6eca1d8ed
|
||||||
|
* - https://www.srf.ch/play/tv/we-myself--why/video/nein-sagen-so-klappt-es?urn=urn:srf:video:6db02b8b-975c-4e3e-8260-f1e6eca1d8e
|
||||||
|
*/
|
||||||
|
const SRF =
|
||||||
|
/^(?:https:\/\/)?(?:www.)?srf.ch\/(?:[\w/-]*)[?&](?:id=|urn=urn:srf:video:)([\w-]+)(?:[&\w=-]*)(?:&?startTime=([\d.]+))?/;
|
||||||
|
|
||||||
export function isYoutubeUrl(url: string) {
|
export function isYoutubeUrl(url: string) {
|
||||||
return YOUTUBE.test(url);
|
return YOUTUBE.test(url);
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,31 @@ import { getVideoId } from '../../src/helpers/video';
|
||||||
import { mount } from '@vue/test-utils';
|
import { mount } from '@vue/test-utils';
|
||||||
import SrfEmbed from '@/components/videos/SrfEmbed.vue';
|
import SrfEmbed from '@/components/videos/SrfEmbed.vue';
|
||||||
|
|
||||||
const url = 'https://www.srf.ch/play/tv/popupvideoplayer?id=6db02b8b-975c-4e3e-8260-f1e6eca1d8ed';
|
describe('Legacy SRF Video Embed', () => {
|
||||||
const embedUrl =
|
const videoId = '6db02b8b-975c-4e3e-8260-f1e6eca1d8ed';
|
||||||
'https://www.srf.ch/play/embed?urn=urn:srf:video:6db02b8b-975c-4e3e-8260-f1e6eca1d8ed&subdivisions=false';
|
const url = `https://www.srf.ch/play/tv/popupvideoplayer?id=${videoId}`;
|
||||||
describe('SRF Video Embed', () => {
|
const embedUrl = `https://www.srf.ch/play/embed?urn=urn:srf:video:${videoId}&subdivisions=false`;
|
||||||
it('should return the correct embed url', () => {
|
it('should return the correct embed url', () => {
|
||||||
const videoId = getVideoId(url);
|
const extractedId = getVideoId(url);
|
||||||
const embedId = '6db02b8b-975c-4e3e-8260-f1e6eca1d8ed';
|
expect(extractedId).toBe(videoId);
|
||||||
expect(videoId).toBe(embedId);
|
});
|
||||||
|
it('should construct the correct iframe', () => {
|
||||||
|
const props = {
|
||||||
|
url,
|
||||||
|
};
|
||||||
|
const wrapper = mount(SrfEmbed, {
|
||||||
|
props,
|
||||||
|
});
|
||||||
|
expect(wrapper.attributes('src')).toBe(embedUrl);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('New SRF Video Embed', () => {
|
||||||
|
const videoId = '6db02b8b-975c-4e3e-8260-f1e6eca1d8ed';
|
||||||
|
const url = `https://www.srf.ch/play/tv/we-myself--why/video/nein-sagen-so-klappt-es?urn=urn:srf:video:${videoId}`;
|
||||||
|
const embedUrl = `https://www.srf.ch/play/embed?urn=urn:srf:video:${videoId}&subdivisions=false`;
|
||||||
|
it('should return the correct embed url', () => {
|
||||||
|
const extractedId = getVideoId(embedUrl);
|
||||||
|
expect(extractedId).toBe(videoId);
|
||||||
});
|
});
|
||||||
it('should construct the correct iframe', () => {
|
it('should construct the correct iframe', () => {
|
||||||
const props = {
|
const props = {
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ from graphene_django import DjangoObjectType
|
||||||
|
|
||||||
from api.utils import get_by_id_or_slug
|
from api.utils import get_by_id_or_slug
|
||||||
from portfolio.models import Project, ProjectEntry
|
from portfolio.models import Project, ProjectEntry
|
||||||
from users.models import Role, UserRole
|
from users.models import Role, UserRole, User
|
||||||
from users.schema import PublicUserNode
|
from users.schema import PublicUserNode
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -13,18 +13,18 @@ class ProjectEntryNode(DjangoObjectType):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ProjectEntry
|
model = ProjectEntry
|
||||||
interfaces = (relay.Node,)
|
interfaces = (relay.Node,)
|
||||||
fields = ("description", "document_url", "project", "created")
|
fields = ('description', 'document_url', 'project', 'created')
|
||||||
|
|
||||||
|
|
||||||
class ProjectNode(DjangoObjectType):
|
class ProjectNode(DjangoObjectType):
|
||||||
pk = graphene.Int()
|
pk = graphene.Int()
|
||||||
entries_count = graphene.Int()
|
entries_count = graphene.Int()
|
||||||
entries = graphene.List(ProjectEntryNode)
|
entries = graphene.List(ProjectEntryNode)
|
||||||
student = graphene.Field(PublicUserNode)
|
owner = graphene.Field(PublicUserNode)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Project
|
model = Project
|
||||||
filter_fields = ["slug", "appearance"]
|
filter_fields = ['slug', 'appearance']
|
||||||
interfaces = (relay.Node,)
|
interfaces = (relay.Node,)
|
||||||
|
|
||||||
def resolve_pk(self, *args, **kwargs):
|
def resolve_pk(self, *args, **kwargs):
|
||||||
|
|
@ -45,16 +45,11 @@ class PortfolioQuery(object):
|
||||||
def resolve_projects(self, info, **kwargs):
|
def resolve_projects(self, info, **kwargs):
|
||||||
user = info.context.user
|
user = info.context.user
|
||||||
if user.is_superuser:
|
if user.is_superuser:
|
||||||
return Project.objects.all().order_by("-pk")
|
return Project.objects.all().order_by('-pk')
|
||||||
|
|
||||||
if (
|
if UserRole.get_role_for_user(user).role == Role.objects.get_default_teacher_role():
|
||||||
UserRole.get_role_for_user(user).role
|
return Project.objects.filter(Q(student__school_classes__in=user.school_classes.all(), final=True) |
|
||||||
== Role.objects.get_default_teacher_role()
|
Q(student=user, final=False)).distinct()
|
||||||
):
|
|
||||||
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)
|
return Project.objects.filter(student=user)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue