blob: 00e2824050cff591e0dee5c09611fa3a84847b4d [file] [log] [blame]
Matthias Andreas Benkard2d4f92e2020-02-09 16:15:07 +01001package eu.mulk.mulkcms2.benki.bookmarks;
2
Matthias Andreas Benkard35e14e42020-02-12 06:20:05 +01003import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
Matthias Andreas Benkard2d4f92e2020-02-09 16:15:07 +01004import static javax.ws.rs.core.MediaType.TEXT_HTML;
5
6import eu.mulk.mulkcms2.benki.accesscontrol.Role;
7import eu.mulk.mulkcms2.benki.users.User;
8import io.quarkus.panache.common.Sort;
9import io.quarkus.qute.Template;
10import io.quarkus.qute.TemplateExtension;
11import io.quarkus.qute.TemplateInstance;
12import io.quarkus.qute.api.ResourcePath;
Matthias Andreas Benkardf20e9b92020-02-10 21:14:57 +010013import io.quarkus.security.Authenticated;
Matthias Andreas Benkard2d4f92e2020-02-09 16:15:07 +010014import io.quarkus.security.identity.SecurityIdentity;
Matthias Andreas Benkard35e14e42020-02-12 06:20:05 +010015import java.io.IOException;
Matthias Andreas Benkardbca94612020-02-10 20:58:13 +010016import java.net.URI;
17import java.net.URISyntaxException;
18import java.time.OffsetDateTime;
Matthias Andreas Benkard2d4f92e2020-02-09 16:15:07 +010019import java.time.format.DateTimeFormatter;
20import java.time.format.FormatStyle;
21import java.time.temporal.TemporalAccessor;
22import java.util.List;
Matthias Andreas Benkardbca94612020-02-10 20:58:13 +010023import java.util.Set;
Matthias Andreas Benkardfc427e22020-02-13 05:00:54 +010024import javax.annotation.CheckForNull;
25import javax.annotation.Nullable;
Matthias Andreas Benkard2d4f92e2020-02-09 16:15:07 +010026import javax.inject.Inject;
Matthias Andreas Benkard35e14e42020-02-12 06:20:05 +010027import javax.json.JsonObject;
Matthias Andreas Benkard2d4f92e2020-02-09 16:15:07 +010028import javax.json.spi.JsonProvider;
Matthias Andreas Benkardbca94612020-02-10 20:58:13 +010029import javax.transaction.Transactional;
30import javax.validation.constraints.NotEmpty;
31import javax.validation.constraints.NotNull;
32import javax.validation.constraints.Pattern;
33import javax.ws.rs.BadRequestException;
34import javax.ws.rs.FormParam;
Matthias Andreas Benkard2d4f92e2020-02-09 16:15:07 +010035import javax.ws.rs.GET;
Matthias Andreas Benkardbca94612020-02-10 20:58:13 +010036import javax.ws.rs.POST;
Matthias Andreas Benkard2d4f92e2020-02-09 16:15:07 +010037import javax.ws.rs.Path;
38import javax.ws.rs.Produces;
Matthias Andreas Benkard35e14e42020-02-12 06:20:05 +010039import javax.ws.rs.QueryParam;
Matthias Andreas Benkardbca94612020-02-10 20:58:13 +010040import javax.ws.rs.core.Response;
Matthias Andreas Benkard2d4f92e2020-02-09 16:15:07 +010041import org.jboss.logging.Logger;
Matthias Andreas Benkard35e14e42020-02-12 06:20:05 +010042import org.jsoup.Jsoup;
Matthias Andreas Benkard2d4f92e2020-02-09 16:15:07 +010043
44@Path("/bookmarks")
45public class BookmarkResource {
46
47 private static Logger log = Logger.getLogger(BookmarkResource.class);
48
49 private static DateTimeFormatter htmlDateFormatter = DateTimeFormatter.ISO_OFFSET_DATE_TIME;
50
51 private static DateTimeFormatter humanDateFormatter =
52 DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG, FormatStyle.SHORT);
53
54 private static JsonProvider jsonProvider = JsonProvider.provider();
55
56 @ResourcePath("benki/bookmarks/bookmarkList.html")
57 @Inject
58 Template bookmarkList;
59
Matthias Andreas Benkardfc427e22020-02-13 05:00:54 +010060 @ResourcePath("benki/bookmarks/newBookmark.html")
61 @Inject
62 Template newBookmark;
63
Matthias Andreas Benkard2d4f92e2020-02-09 16:15:07 +010064 @Inject SecurityIdentity identity;
65
66 @GET
67 @Produces(TEXT_HTML)
Matthias Andreas Benkardbca94612020-02-10 20:58:13 +010068 public TemplateInstance getIndex() {
Matthias Andreas Benkard2d4f92e2020-02-09 16:15:07 +010069 List<Bookmark> bookmarks;
70 if (identity.isAnonymous()) {
71 Role world = Role.find("from Role r join r.tags tag where tag = 'world'").singleResult();
72 bookmarks =
73 Bookmark.find(
74 "select bm from Bookmark bm join bm.targets target left join fetch bm.owner where target = ?1",
75 Sort.by("date").descending(),
76 world)
77 .list();
78 } else {
79 var userName = identity.getPrincipal().getName();
80 User user =
81 User.find("from BenkiUser u join u.nicknames n where ?1 = n", userName).singleResult();
82 bookmarks =
83 Bookmark.find(
84 "select bm from BenkiUser u inner join u.visibleBookmarks bm left join fetch bm.owner where u.id = ?1",
85 Sort.by("date").descending(),
86 user.id)
87 .list();
88 }
Matthias Andreas Benkard35e14e42020-02-12 06:20:05 +010089 return bookmarkList.data("bookmarks", bookmarks).data("authenticated", !identity.isAnonymous());
Matthias Andreas Benkardbca94612020-02-10 20:58:13 +010090 }
91
Matthias Andreas Benkardfc427e22020-02-13 05:00:54 +010092 @GET
93 @Authenticated
94 @Path("new")
95 @Produces(TEXT_HTML)
96 public TemplateInstance getNewBookmarkForm(
97 @QueryParam("uri") @CheckForNull String uri,
98 @QueryParam("title") @CheckForNull String title,
99 @QueryParam("description") @CheckForNull String description) {
100 return newBookmark.data("uri", uri).data("title", title).data("description", description);
101 }
102
Matthias Andreas Benkardbca94612020-02-10 20:58:13 +0100103 @POST
104 @Transactional
Matthias Andreas Benkardf20e9b92020-02-10 21:14:57 +0100105 @Authenticated
Matthias Andreas Benkardbca94612020-02-10 20:58:13 +0100106 public Response postBookmark(
107 @FormParam("uri") URI uri,
108 @FormParam("title") @NotEmpty String title,
109 @FormParam("description") String description,
Matthias Andreas Benkard35e14e42020-02-12 06:20:05 +0100110 @FormParam("visibility") @NotNull @Pattern(regexp = "public|semiprivate|private")
111 String visibility)
Matthias Andreas Benkardbca94612020-02-10 20:58:13 +0100112 throws URISyntaxException {
113
114 var userName = identity.getPrincipal().getName();
115 User user =
116 User.find("from BenkiUser u join u.nicknames n where ?1 = n", userName).singleResult();
117
118 var bookmark = new Bookmark();
119 bookmark.uri = uri.toString();
120 bookmark.title = title;
121 bookmark.tags = Set.of();
122 bookmark.description = description != null ? description : "";
123 bookmark.owner = user;
124 bookmark.date = OffsetDateTime.now();
125
126 if (visibility.equals("public")) {
127 Role world = Role.find("from Role r join r.tags tag where tag = 'world'").singleResult();
128 bookmark.targets = Set.of(world);
129 } else if (visibility.equals("semiprivate")) {
130 bookmark.targets = Set.copyOf(user.defaultTargets);
131 } else if (!visibility.equals("private")) {
132 throw new BadRequestException(String.format("invalid visibility ā€œ%sā€", visibility));
133 }
134
135 bookmark.persistAndFlush();
136
137 return Response.seeOther(new URI("/bookmarks")).build();
Matthias Andreas Benkard2d4f92e2020-02-09 16:15:07 +0100138 }
139
Matthias Andreas Benkard35e14e42020-02-12 06:20:05 +0100140 @GET
141 @Path("page-info")
142 @Authenticated
143 @Produces(APPLICATION_JSON)
144 public JsonObject getPageInfo(@QueryParam("uri") URI uri) throws IOException {
145 var document = Jsoup.connect(uri.toString()).get();
146 return jsonProvider.createObjectBuilder().add("title", document.title()).build();
147 }
148
Matthias Andreas Benkard2d4f92e2020-02-09 16:15:07 +0100149 @TemplateExtension
150 static String humanDateTime(TemporalAccessor x) {
151 return humanDateFormatter.format(x);
152 }
153
154 @TemplateExtension
155 static String htmlDateTime(TemporalAccessor x) {
156 return htmlDateFormatter.format(x);
157 }
158}