Skip to content

Commit 81d9862

Browse files
committed
WIP: add playlist feature
1 parent d8374a2 commit 81d9862

File tree

15 files changed

+937
-0
lines changed

15 files changed

+937
-0
lines changed

modules/graphql/pom.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,16 @@
168168
<version>${project.version}</version>
169169
<scope>compile</scope>
170170
</dependency>
171+
<dependency>
172+
<groupId>org.opencastproject</groupId>
173+
<artifactId>opencast-playlists</artifactId>
174+
<version>${project.version}</version>
175+
<scope>compile</scope>
176+
</dependency>
177+
<dependency>
178+
<groupId>org.easymock</groupId>
179+
<artifactId>easymock</artifactId>
180+
</dependency>
171181
</dependencies>
172182
<build>
173183
<plugins>
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*
2+
* Licensed to The Apereo Foundation under one or more contributor license
3+
* agreements. See the NOTICE file distributed with this work for additional
4+
* information regarding copyright ownership.
5+
*
6+
*
7+
* The Apereo Foundation licenses this file to you under the Educational
8+
* Community License, Version 2.0 (the "License"); you may not use this file
9+
* except in compliance with the License. You may obtain a copy of the License
10+
* at:
11+
*
12+
* http://opensource.org/licenses/ecl2.txt
13+
*
14+
* Unless required by applicable law or agreed to in writing, software
15+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
16+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
17+
* License for the specific language governing permissions and limitations under
18+
* the License.
19+
*
20+
*/
21+
22+
package org.opencastproject.graphql.datafetcher.playlist;
23+
24+
import org.opencastproject.graphql.datafetcher.ContextDataFetcher;
25+
import org.opencastproject.graphql.exception.GraphQLRuntimeException;
26+
import org.opencastproject.graphql.exception.OpencastErrorType;
27+
import org.opencastproject.graphql.execution.context.OpencastContext;
28+
import org.opencastproject.graphql.playlist.GqlPlaylist;
29+
import org.opencastproject.playlists.Playlist;
30+
import org.opencastproject.playlists.PlaylistService;
31+
import org.opencastproject.security.api.UnauthorizedException;
32+
import org.opencastproject.util.NotFoundException;
33+
34+
import java.util.Objects;
35+
36+
import graphql.schema.DataFetchingEnvironment;
37+
38+
public class PlaylistDataFetcher implements ContextDataFetcher<GqlPlaylist> {
39+
40+
private final String playlistId;
41+
42+
public PlaylistDataFetcher(String playlistId) {
43+
Objects.requireNonNull(playlistId, "Playlist identifier must not be null.");
44+
this.playlistId = playlistId;
45+
}
46+
47+
@Override
48+
public GqlPlaylist get(OpencastContext opencastContext, DataFetchingEnvironment dataFetchingEnvironment) {
49+
PlaylistService playlistService = opencastContext.getService(PlaylistService.class);
50+
51+
try {
52+
Playlist playlist = playlistService.getPlaylistById(playlistId);
53+
if (playlist == null) {
54+
return null;
55+
}
56+
// enrich if available
57+
try {
58+
playlist = playlistService.enrich(playlist).toPlaylist();
59+
} catch (Throwable ignored) {
60+
// If enrich is not available or fails, fall back to original playlist
61+
}
62+
return new GqlPlaylist(playlist);
63+
} catch (NotFoundException e) {
64+
return null;
65+
} catch (UnauthorizedException e) {
66+
throw new GraphQLRuntimeException("Unauthorized", OpencastErrorType.Unauthorized, e);
67+
} catch (Exception e) {
68+
throw new GraphQLRuntimeException("Error fetching playlist", OpencastErrorType.InternalError, e);
69+
}
70+
}
71+
}
72+
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* Licensed to The Apereo Foundation under one or more contributor license
3+
* agreements. See the NOTICE file distributed with this work for additional
4+
* information regarding copyright ownership.
5+
*
6+
*
7+
* The Apereo Foundation licenses this file to you under the Educational
8+
* Community License, Version 2.0 (the "License"); you may not use this file
9+
* except in compliance with the License. You may obtain a copy of the License
10+
* at:
11+
*
12+
* http://opensource.org/licenses/ecl2.txt
13+
*
14+
* Unless required by applicable law or agreed to in writing, software
15+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
16+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
17+
* License for the specific language governing permissions and limitations under
18+
* the License.
19+
*
20+
*/
21+
22+
package org.opencastproject.graphql.datafetcher.playlist;
23+
24+
import org.opencastproject.graphql.datafetcher.ElasticsearchDataFetcher;
25+
import org.opencastproject.graphql.execution.context.OpencastContext;
26+
import org.opencastproject.graphql.playlist.GqlPlaylistList;
27+
import org.opencastproject.playlists.Playlist;
28+
import org.opencastproject.playlists.PlaylistService;
29+
30+
import java.util.ArrayList;
31+
import java.util.List;
32+
33+
import graphql.schema.DataFetchingEnvironment;
34+
35+
public class PlaylistOffsetDataFetcher extends ElasticsearchDataFetcher<GqlPlaylistList> {
36+
37+
@Override
38+
public GqlPlaylistList get(OpencastContext opencastContext, DataFetchingEnvironment dataFetchingEnvironment) {
39+
PlaylistService playlistService = opencastContext.getService(PlaylistService.class);
40+
41+
Integer limit = parseParam("limit", DEFAULT_PAGE_SIZE, dataFetchingEnvironment);
42+
Integer offset = parseParam("offset", 0, dataFetchingEnvironment);
43+
44+
List<Playlist> playlists = new ArrayList<>();
45+
for (Playlist p: playlistService.getPlaylists(limit, offset)) {
46+
playlists.add(playlistService.enrich(p).toPlaylist());
47+
}
48+
return new GqlPlaylistList(playlists, limit, offset);
49+
}
50+
51+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
* Licensed to The Apereo Foundation under one or more contributor license
3+
* agreements. See the NOTICE file distributed with this work for additional
4+
* information regarding copyright ownership.
5+
*
6+
*
7+
* The Apereo Foundation licenses this file to you under the Educational
8+
* Community License, Version 2.0 (the "License"); you may not use this file
9+
* except in compliance with the License. You may obtain a copy of the License
10+
* at:
11+
*
12+
* http://opensource.org/licenses/ecl2.txt
13+
*
14+
* Unless required by applicable law or agreed to in writing, software
15+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
16+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
17+
* License for the specific language governing permissions and limitations under
18+
* the License.
19+
*
20+
*/
21+
22+
package org.opencastproject.graphql.playlist;
23+
24+
import org.opencastproject.graphql.datafetcher.event.EventDataFetcher;
25+
import org.opencastproject.graphql.type.output.GqlPublication;
26+
import org.opencastproject.playlists.PlaylistEntry;
27+
28+
import java.util.Collections;
29+
import java.util.List;
30+
import java.util.stream.Collectors;
31+
32+
import graphql.annotations.annotationTypes.GraphQLDescription;
33+
import graphql.annotations.annotationTypes.GraphQLField;
34+
import graphql.annotations.annotationTypes.GraphQLName;
35+
import graphql.schema.DataFetchingEnvironment;
36+
37+
@GraphQLName(GqlEventPlaylistEntry.TYPE_NAME)
38+
@GraphQLDescription("An entry in a playlist.")
39+
public class GqlEventPlaylistEntry implements GqlPlaylistEntry {
40+
41+
public static final String TYPE_NAME = "EventPlaylistEntry";
42+
43+
private final PlaylistEntry entry;
44+
45+
public GqlEventPlaylistEntry(PlaylistEntry entry) {
46+
this.entry = entry;
47+
}
48+
49+
@Override
50+
public PlaylistEntry getEntry() {
51+
return entry;
52+
}
53+
54+
@GraphQLField
55+
public List<GqlPublication> publication(final DataFetchingEnvironment environment) {
56+
var event = new EventDataFetcher(contentId()).get(environment);
57+
if (event == null) {
58+
return Collections.emptyList();
59+
}
60+
return event.getEvent().getPublications().stream().map(GqlPublication::new).collect(Collectors.toList());
61+
}
62+
63+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Licensed to The Apereo Foundation under one or more contributor license
3+
* agreements. See the NOTICE file distributed with this work for additional
4+
* information regarding copyright ownership.
5+
*
6+
*
7+
* The Apereo Foundation licenses this file to you under the Educational
8+
* Community License, Version 2.0 (the "License"); you may not use this file
9+
* except in compliance with the License. You may obtain a copy of the License
10+
* at:
11+
*
12+
* http://opensource.org/licenses/ecl2.txt
13+
*
14+
* Unless required by applicable law or agreed to in writing, software
15+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
16+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
17+
* License for the specific language governing permissions and limitations under
18+
* the License.
19+
*
20+
*/
21+
22+
package org.opencastproject.graphql.playlist;
23+
24+
import org.opencastproject.playlists.PlaylistEntry;
25+
26+
import graphql.annotations.annotationTypes.GraphQLDescription;
27+
import graphql.annotations.annotationTypes.GraphQLName;
28+
29+
@GraphQLName(GqlInaccessiblePlaylistEntry.TYPE_NAME)
30+
@GraphQLDescription("An entry in a playlist.")
31+
public class GqlInaccessiblePlaylistEntry implements GqlPlaylistEntry {
32+
33+
public static final String TYPE_NAME = "InaccessiblePlaylistEntry";
34+
35+
private final PlaylistEntry entry;
36+
37+
public GqlInaccessiblePlaylistEntry(PlaylistEntry entry) {
38+
this.entry = entry;
39+
}
40+
41+
@Override
42+
public PlaylistEntry getEntry() {
43+
return entry;
44+
}
45+
46+
}
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
/*
2+
* Licensed to The Apereo Foundation under one or more contributor license
3+
* agreements. See the NOTICE file distributed with this work for additional
4+
* information regarding copyright ownership.
5+
*
6+
*
7+
* The Apereo Foundation licenses this file to you under the Educational
8+
* Community License, Version 2.0 (the "License"); you may not use this file
9+
* except in compliance with the License. You may obtain a copy of the License
10+
* at:
11+
*
12+
* http://opensource.org/licenses/ecl2.txt
13+
*
14+
* Unless required by applicable law or agreed to in writing, software
15+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
16+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
17+
* License for the specific language governing permissions and limitations under
18+
* the License.
19+
*
20+
*/
21+
22+
package org.opencastproject.graphql.playlist;
23+
24+
import org.opencastproject.graphql.type.DateTimeFunction;
25+
import org.opencastproject.playlists.Playlist;
26+
import org.opencastproject.playlists.PlaylistAccessControlEntry;
27+
import org.opencastproject.playlists.PlaylistEntry;
28+
29+
import java.time.OffsetDateTime;
30+
import java.time.ZoneOffset;
31+
import java.util.LinkedList;
32+
import java.util.List;
33+
import java.util.stream.Collectors;
34+
35+
import graphql.annotations.annotationTypes.GraphQLDescription;
36+
import graphql.annotations.annotationTypes.GraphQLField;
37+
import graphql.annotations.annotationTypes.GraphQLID;
38+
import graphql.annotations.annotationTypes.GraphQLName;
39+
import graphql.annotations.annotationTypes.GraphQLNonNull;
40+
import graphql.annotations.annotationTypes.GraphQLType;
41+
42+
@GraphQLName(GqlPlaylist.TYPE_NAME)
43+
@GraphQLDescription("A playlist of events.")
44+
public class GqlPlaylist {
45+
46+
public static final String TYPE_NAME = "Playlist";
47+
48+
private final Playlist playlist;
49+
50+
public GqlPlaylist(Playlist playlist) {
51+
this.playlist = playlist;
52+
}
53+
54+
@GraphQLID
55+
@GraphQLField
56+
@GraphQLNonNull
57+
public String id() {
58+
return playlist.getId();
59+
}
60+
61+
@GraphQLField
62+
public LinkedList<GqlPlaylistEntry> entries() {
63+
List<PlaylistEntry> entries = playlist.getEntries();
64+
if (entries == null) {
65+
return new LinkedList<>();
66+
}
67+
return entries.stream().map(e -> switch (e.getType()) {
68+
case EVENT -> new GqlEventPlaylistEntry(e);
69+
case INACCESSIBLE -> new GqlInaccessiblePlaylistEntry(e);
70+
}).collect(Collectors.toCollection(LinkedList::new));
71+
}
72+
73+
@GraphQLField
74+
public String title() {
75+
return playlist.getTitle();
76+
}
77+
78+
@GraphQLField
79+
public String description() {
80+
return playlist.getDescription();
81+
}
82+
83+
@GraphQLField
84+
public String creator() {
85+
return playlist.getCreator();
86+
}
87+
88+
@GraphQLField
89+
@GraphQLType(DateTimeFunction.class)
90+
public OffsetDateTime updated() {
91+
return playlist.getUpdated().toInstant().atOffset(ZoneOffset.UTC);
92+
}
93+
94+
@GraphQLField
95+
public LinkedList<GqlPlaylistAccessControlEntry> accessControlEntries() {
96+
List<PlaylistAccessControlEntry> aces = playlist.getAccessControlEntries();
97+
if (aces == null) {
98+
return new LinkedList<>();
99+
}
100+
return aces.stream().map(GqlPlaylistAccessControlEntry::new)
101+
.collect(Collectors.toCollection(LinkedList::new));
102+
}
103+
104+
public Playlist getPlaylist() {
105+
return playlist;
106+
}
107+
108+
}

0 commit comments

Comments
 (0)