From: David ‘Bombe’ Roden Date: Tue, 22 Mar 2011 18:46:01 +0000 (+0100) Subject: Merge branch 'next' into image-management X-Git-Tag: beta-freefall-0.6.2-1~101 X-Git-Url: https://git.pterodactylus.net/?p=Sone.git;a=commitdiff_plain;h=33f333b35a73d3d4a4e79f41e9dd7b342db87b1a;hp=cd1a52cf4426d23240d59be0a433d8f1763f2911 Merge branch 'next' into image-management Conflicts: src/main/java/net/pterodactylus/sone/core/Core.java src/main/java/net/pterodactylus/sone/data/Sone.java src/main/java/net/pterodactylus/sone/web/WebInterface.java src/main/resources/i18n/sone.en.properties --- diff --git a/src/main/java/net/pterodactylus/sone/core/Core.java b/src/main/java/net/pterodactylus/sone/core/Core.java index 7dc398e..d61211d 100644 --- a/src/main/java/net/pterodactylus/sone/core/Core.java +++ b/src/main/java/net/pterodactylus/sone/core/Core.java @@ -31,7 +31,9 @@ import java.util.logging.Logger; import net.pterodactylus.sone.core.Options.DefaultOption; import net.pterodactylus.sone.core.Options.Option; import net.pterodactylus.sone.core.Options.OptionWatcher; +import net.pterodactylus.sone.data.Album; import net.pterodactylus.sone.data.Client; +import net.pterodactylus.sone.data.Image; import net.pterodactylus.sone.data.Post; import net.pterodactylus.sone.data.Profile; import net.pterodactylus.sone.data.Profile.Field; @@ -165,6 +167,12 @@ public class Core implements IdentityListener, UpdateListener { /** Trusted identities, sorted by own identities. */ private Map> trustedIdentities = Collections.synchronizedMap(new HashMap>()); + /** All known albums. */ + private Map albums = new HashMap(); + + /** All known images. */ + private Map images = new HashMap(); + /** * Creates a new core. * @@ -722,6 +730,76 @@ public class Core implements IdentityListener, UpdateListener { return posts; } + /** + * + * Returns the album with the given ID, creating a new album if no album + * with the given ID can be found. + * + * @param albumId + * The ID of the album + * @return The album with the given ID + */ + public Album getAlbum(String albumId) { + return getAlbum(albumId, true); + } + + /** + * Returns the album with the given ID, optionally creating a new album if + * an album with the given ID can not be found. + * + * @param albumId + * The ID of the album + * @param create + * {@code true} to create a new album if none exists for the + * given ID + * @return The album with the given ID, or {@code null} if no album with the + * given ID exists and {@code create} is {@code false} + */ + public Album getAlbum(String albumId, boolean create) { + synchronized (albums) { + Album album = albums.get(albumId); + if (create && (album == null)) { + album = new Album(albumId); + albums.put(albumId, album); + } + return album; + } + } + + /** + * Returns the image with the given ID, creating it if necessary. + * + * @param imageId + * The ID of the image + * @return The image with the given ID + */ + public Image getImage(String imageId) { + return getImage(imageId, true); + } + + /** + * Returns the image with the given ID, optionally creating it if it does + * not exist. + * + * @param imageId + * The ID of the image + * @param create + * {@code true} to create an image if none exists with the given + * ID + * @return The image with the given ID, or {@code null} if none exists and + * none was created + */ + public Image getImage(String imageId, boolean create) { + synchronized (images) { + Image image = images.get(imageId); + if (create && (image == null)) { + image = new Image(imageId); + images.put(imageId, image); + } + return image; + } + } + // // ACTIONS // @@ -1605,6 +1683,40 @@ public class Core implements IdentityListener, UpdateListener { } /** + * Creates a new top-level album for the given Sone. + * + * @param sone + * The Sone to create the album for + * @return The new album + */ + public Album createAlbum(Sone sone) { + return createAlbum(sone, null); + } + + /** + * Creates a new album for the given Sone. + * + * @param sone + * The Sone to create the album for + * @param parent + * The parent of the album (may be {@code null} to create a + * top-level album) + * @return The new album + */ + public Album createAlbum(Sone sone, Album parent) { + Album album = new Album(); + synchronized (albums) { + albums.put(album.getId(), album); + } + album.setSone(sone); + if (parent != null) { + parent.addAlbum(album); + } + sone.addAlbum(album); + return album; + } + + /** * Starts the core. */ public void start() { diff --git a/src/main/java/net/pterodactylus/sone/data/Album.java b/src/main/java/net/pterodactylus/sone/data/Album.java new file mode 100644 index 0000000..4f52f50 --- /dev/null +++ b/src/main/java/net/pterodactylus/sone/data/Album.java @@ -0,0 +1,299 @@ +/* + * Sone - Album.java - Copyright © 2011 David Roden + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package net.pterodactylus.sone.data; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +import net.pterodactylus.util.validation.Validation; + +/** + * Container for images that can also contain nested {@link Album}s. + * + * @author David ‘Bombe’ Roden + */ +public class Album implements Fingerprintable { + + /** The ID of this album. */ + private final String id; + + /** The Sone this album belongs to. */ + private Sone sone; + + /** Nested albums. */ + private final List albums = new ArrayList(); + + /** The images in this album. */ + private final List images = new ArrayList(); + + /** The parent album. */ + private Album parent; + + /** The name of this album. */ + private String name; + + /** The description of this album. */ + private String description; + + /** + * Creates a new album with a random ID. + */ + public Album() { + this(UUID.randomUUID().toString()); + } + + /** + * Creates a new album with the given ID. + * + * @param id + * The ID of the album + */ + public Album(String id) { + Validation.begin().isNotNull("Album ID", id).check(); + this.id = id; + } + + // + // ACCESSORS + // + + /** + * Returns the ID of this album. + * + * @return The ID of this album + */ + public String getId() { + return id; + } + + /** + * Returns the Sone this album belongs to. + * + * @return The Sone this album belongs to + */ + public Sone getSone() { + return sone; + } + + /** + * Sets the owner of the album. The owner can only be set as long as the + * current owner is {@code null}. + * + * @param sone + * The album owner + * @return This album + */ + public Album setSone(Sone sone) { + Validation.begin().isNull("Current Album Owner", this.sone).isNotNull("New Album Owner", sone).check(); + this.sone = sone; + return this; + } + + /** + * Returns the nested albums. + * + * @return The nested albums + */ + public List getAlbums() { + return new ArrayList(albums); + } + + /** + * Adds an album to this album. + * + * @param album + * The album to add + */ + public void addAlbum(Album album) { + Validation.begin().isNotNull("Album", album).check().isEqual("Album Owner", album.sone, sone).isNull("Album Parent", album.parent).check(); + albums.add(album); + album.setParent(this); + } + + /** + * Removes an album from this album. + * + * @param album + * The album to remove + */ + public void removeAlbum(Album album) { + Validation.begin().isNotNull("Album", album).check().isEqual("Album Owner", album.sone, sone).isEqual("Album Parent", album.parent, this).check(); + albums.remove(album); + album.removeParent(); + } + + /** + * Returns the images in this album. + * + * @return The images in this album + */ + public List getImages() { + return new ArrayList(images); + } + + /** + * Adds the given image to this album. + * + * @param image + * The image to add + */ + public void addImage(Image image) { + Validation.begin().isNotNull("Image", image).check().isEqual("Image Owner", image.getSone(), sone).check(); + images.add(image); + } + + /** + * Removes the given image from this album. + * + * @param image + * The image to remove + */ + public void removeImage(Image image) { + Validation.begin().isNotNull("Image", image).check().isEqual("Image Owner", image.getSone(), sone).check(); + images.remove(image); + } + + /** + * Returns the parent album of this album. + * + * @return The parent album of this album, or {@code null} if this album + * does not have a parent + */ + public Album getParent() { + return parent; + } + + /** + * Sets the parent album of this album. + * + * @param parent + * The new parent album of this album + * @return This album + */ + protected Album setParent(Album parent) { + Validation.begin().isNotNull("Album Parent", parent).check(); + this.parent = parent; + return this; + } + + /** + * Removes the parent album of this album. + * + * @return This album + */ + protected Album removeParent() { + Validation.begin().isNotNull("Album Parent", parent).check(); + this.parent = null; + return this; + } + + /** + * Returns the name of this album. + * + * @return The name of this album + */ + public String getName() { + return name; + } + + /** + * Sets the name of this album. + * + * @param name + * The name of this album + * @return This album + */ + public Album setName(String name) { + Validation.begin().isNotNull("Album Name", name).check(); + this.name = name; + return this; + } + + /** + * Returns the description of this album. + * + * @return The description of this album + */ + public String getDescription() { + return description; + } + + /** + * Sets the description of this album. + * + * @param description + * The description of this album + * @return This album + */ + public Album setDescription(String description) { + Validation.begin().isNotNull("Album Description", description).check(); + this.description = description; + return this; + } + + // + // FINGERPRINTABLE METHODS + // + + /** + * {@inheritDoc} + */ + @Override + public String getFingerprint() { + StringBuilder fingerprint = new StringBuilder(); + fingerprint.append("Album("); + fingerprint.append("ID(").append(id).append(')'); + fingerprint.append("Name(").append(name).append(')'); + fingerprint.append("Description(").append(description).append(')'); + + /* add nested albums. */ + fingerprint.append("Albums("); + for (Album album : albums) { + fingerprint.append(album.getFingerprint()); + } + fingerprint.append(')'); + + /* add images. */ + fingerprint.append("Images("); + for (Image image : images) { + fingerprint.append(image.getFingerprint()); + } + fingerprint.append(')'); + + fingerprint.append(')'); + return fingerprint.toString(); + } + + // + // OBJECT METHODS + // + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object object) { + if (!(object instanceof Album)) { + return false; + } + Album album = (Album) object; + return id.equals(album.id); + } + +} diff --git a/src/main/java/net/pterodactylus/sone/data/Image.java b/src/main/java/net/pterodactylus/sone/data/Image.java new file mode 100644 index 0000000..587c15e --- /dev/null +++ b/src/main/java/net/pterodactylus/sone/data/Image.java @@ -0,0 +1,264 @@ +/* + * Sone - Image.java - Copyright © 2011 David Roden + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package net.pterodactylus.sone.data; + +import java.util.UUID; + +import net.pterodactylus.util.validation.Validation; + +/** + * Container for image metadata. + * + * @author David ‘Bombe’ Roden + */ +public class Image implements Fingerprintable { + + /** The ID of the image. */ + private final String id; + + /** The Sone the image belongs to. */ + private Sone sone; + + /** The key of the image. */ + private String key; + + /** The creation time of the image. */ + private long creationTime; + + /** The width of the image. */ + private int width; + + /** The height of the image. */ + private int height; + + /** The title of the image. */ + private String title; + + /** The description of the image. */ + private String description; + + /** + * Creates a new image with a random ID. + */ + public Image() { + this(UUID.randomUUID().toString()); + } + + /** + * Creates a new image. + * + * @param id + * The ID of the image + */ + public Image(String id) { + Validation.begin().isNotNull("Image ID", id).check(); + this.id = id; + } + + // + // ACCESSORS + // + + /** + * Returns the ID of this image. + * + * @return The ID of this image + */ + public String getId() { + return id; + } + + /** + * Returns the Sone this image belongs to. + * + * @return The Sone this image belongs to + */ + public Sone getSone() { + return sone; + } + + /** + * Sets the owner of this image. The owner can only be set if no owner has + * yet been set. + * + * @param sone + * The new owner of this image + * @return This image + */ + public Image setSone(Sone sone) { + Validation.begin().isNull("Current Image Owner", this.sone).isNotNull("New Image Owner", sone); + this.sone = sone; + return this; + } + + /** + * Returns the key of this image. + * + * @return The key of this image + */ + public String getKey() { + return key; + } + + /** + * Sets the key of this image. The key can only be set as long as no key has + * yet been set. + * + * @param key + * The new key of this image + * @return This image + */ + public Image setKey(String key) { + Validation.begin().isNull("Current Image Key", this.key).isNotNull("New Image Key", key).check(); + this.key = key; + return this; + } + + /** + * Returns the creation time of this image. + * + * @return The creation time of this image (in milliseconds since 1970, Jan + * 1, UTC) + */ + public long getCreationTime() { + return creationTime; + } + + /** + * Sets the new creation time of this image. The creation time can only be + * set as long as no creation time has been set yet. + * + * @param creationTime + * The new creation time of this image + * @return This image + */ + public Image setCreationTime(long creationTime) { + Validation.begin().isEqual("Current Image Creation Time", this.creationTime, 0).isGreater("New Image Creation Time", creationTime, 0).check(); + this.creationTime = creationTime; + return this; + } + + /** + * Returns the width of this image. + * + * @return The width of this image (in pixels) + */ + public int getWidth() { + return width; + } + + /** + * Sets the width of this image. The width can only be set as long as no + * width has been set yet. + * + * @param width + * The new width of this image + * @return This image + */ + public Image setWidth(int width) { + Validation.begin().isEqual("Current Image Width", this.width, 0).isGreater("New Image Width", width, 0).check(); + this.width = width; + return this; + } + + /** + * Returns the height of this image. + * + * @return The height of this image (in pixels) + */ + public int getHeight() { + return height; + } + + /** + * Sets the new height of this image. The height can only be set as long as + * no height has yet been set. + * + * @param height + * The new height of this image + * @return This image + */ + public Image setHeight(int height) { + Validation.begin().isEqual("Current Image Height", this.height, 0).isGreater("New Image Height", height, 0); + this.height = height; + return this; + } + + /** + * Returns the title of this image. + * + * @return The title of this image + */ + public String getTitle() { + return title; + } + + /** + * Sets the title of this image. + * + * @param title + * The title of this image + * @return This image + */ + public Image setTitle(String title) { + Validation.begin().isNotNull("Image Title", title).check(); + this.title = title; + return this; + } + + /** + * Returns the description of this image. + * + * @return The description of this image + */ + public String getDescription() { + return description; + } + + /** + * Sets the description of this image. + * + * @param description + * The description of this image + * @return This image + */ + public Image setDescription(String description) { + Validation.begin().isNotNull("Image Description", description).check(); + this.description = description; + return this; + } + + // + // FINGERPRINTABLE METHODS + // + + /** + * {@inheritDoc} + */ + @Override + public String getFingerprint() { + StringBuilder fingerprint = new StringBuilder(); + fingerprint.append("Image("); + fingerprint.append("ID(").append(id).append(')'); + fingerprint.append("Title(").append(title).append(')'); + fingerprint.append("Description(").append(description).append(')'); + fingerprint.append(')'); + return fingerprint.toString(); + } + +} diff --git a/src/main/java/net/pterodactylus/sone/data/Sone.java b/src/main/java/net/pterodactylus/sone/data/Sone.java index cc54697..23bbb3e 100644 --- a/src/main/java/net/pterodactylus/sone/data/Sone.java +++ b/src/main/java/net/pterodactylus/sone/data/Sone.java @@ -30,6 +30,7 @@ import java.util.logging.Logger; import net.pterodactylus.sone.freenet.wot.Identity; import net.pterodactylus.sone.template.SoneAccessor; import net.pterodactylus.util.logging.Logging; +import net.pterodactylus.util.validation.Validation; import freenet.keys.FreenetURI; /** @@ -99,6 +100,9 @@ public class Sone implements Fingerprintable, Comparable { /** The IDs of all liked replies. */ private final Set likedReplyIds = Collections.synchronizedSet(new HashSet()); + /** The albums of this Sone. */ + private final List albums = Collections.synchronizedList(new ArrayList()); + /** * Creates a new Sone. * @@ -580,6 +584,37 @@ public class Sone implements Fingerprintable, Comparable { return this; } + /** + * Returns the albums of this Sone. + * + * @return The albums of this Sone + */ + public List getAlbums() { + return Collections.unmodifiableList(albums); + } + + /** + * Adds an album to this Sone. + * + * @param album + * The album to add + */ + public synchronized void addAlbum(Album album) { + Validation.begin().isNotNull("Album", album).check().isEqual("Album Owner", album.getSone(), this).check(); + albums.add(album); + } + + /** + * Removes an album from this Sone. + * + * @param album + * The album to remove + */ + public synchronized void removeAlbum(Album album) { + Validation.begin().isNotNull("Album", album).check().isEqual("Album Owner", album.getSone(), this).check(); + albums.remove(album); + } + // // FINGERPRINTABLE METHODS // @@ -622,6 +657,12 @@ public class Sone implements Fingerprintable, Comparable { } fingerprint.append(')'); + fingerprint.append("Albums("); + for (Album album : albums) { + fingerprint.append(album.getFingerprint()); + } + fingerprint.append(')'); + return fingerprint.toString(); } diff --git a/src/main/java/net/pterodactylus/sone/template/AlbumAccessor.java b/src/main/java/net/pterodactylus/sone/template/AlbumAccessor.java new file mode 100644 index 0000000..5042995 --- /dev/null +++ b/src/main/java/net/pterodactylus/sone/template/AlbumAccessor.java @@ -0,0 +1,78 @@ +/* + * Sone - AlbumAccessor.java - Copyright © 2011 David Roden + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package net.pterodactylus.sone.template; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import net.pterodactylus.sone.data.Album; +import net.pterodactylus.util.template.Accessor; +import net.pterodactylus.util.template.ReflectionAccessor; +import net.pterodactylus.util.template.TemplateContext; + +/** + * {@link Accessor} implementation for {@link Album}s. A property named + * “backlinks” is added, it returns links to all parents and the owner Sone of + * an album. + * + * @author David ‘Bombe’ Roden + */ +public class AlbumAccessor extends ReflectionAccessor { + + /** + * {@inheritDoc} + */ + @Override + public Object get(TemplateContext templateContext, Object object, String member) { + Album album = (Album) object; + if ("backlinks".equals(member)) { + List> backlinks = new ArrayList>(); + Album currentAlbum = album; + while (currentAlbum != null) { + backlinks.add(0, createLink("imageBrowser.html?album=" + album.getId(), album.getName())); + currentAlbum = currentAlbum.getParent(); + } + backlinks.add(0, createLink("viewSone.html?sone=" + album.getSone().getId(), SoneAccessor.getNiceName(album.getSone()))); + return backlinks; + } + return super.get(templateContext, object, member); + } + + // + // PRIVATE METHODS + // + + /** + * Creates a map containing mappings for “target” and “link.” + * + * @param target + * The target to link to + * @param name + * The name of the link + * @return The created map containing the mappings + */ + private Map createLink(String target, String name) { + Map link = new HashMap(); + link.put("target", target); + link.put("name", name); + return link; + } + +} diff --git a/src/main/java/net/pterodactylus/sone/web/CreateAlbumPage.java b/src/main/java/net/pterodactylus/sone/web/CreateAlbumPage.java new file mode 100644 index 0000000..7b51fb5 --- /dev/null +++ b/src/main/java/net/pterodactylus/sone/web/CreateAlbumPage.java @@ -0,0 +1,70 @@ +/* + * Sone - CreateAlbumPage.java - Copyright © 2011 David Roden + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package net.pterodactylus.sone.web; + +import net.pterodactylus.sone.data.Album; +import net.pterodactylus.sone.data.Sone; +import net.pterodactylus.sone.web.page.Page.Request.Method; +import net.pterodactylus.util.template.Template; +import net.pterodactylus.util.template.TemplateContext; + +/** + * Page that lets the user create a new album. + * + * @author David ‘Bombe’ Roden + */ +public class CreateAlbumPage extends SoneTemplatePage { + + /** + * Creates a new “create album” page. + * + * @param template + * The template to render + * @param webInterface + * The Sone web interface + */ + public CreateAlbumPage(Template template, WebInterface webInterface) { + super("createAlbum.html", template, "Page.CreateAlbum.Title", webInterface, true); + } + + // + // SONETEMPLATEPAGE METHODS + // + + /** + * {@inheritDoc} + */ + @Override + protected void processTemplate(Request request, TemplateContext templateContext) throws RedirectException { + super.processTemplate(request, templateContext); + if (request.getMethod() == Method.POST) { + String name = request.getHttpRequest().getPartAsStringFailsafe("name", 64).trim(); + if (name.length() == 0) { + templateContext.set("nameMissing", true); + return; + } + Sone currentSone = getCurrentSone(request.getToadletContext()); + String parentId = request.getHttpRequest().getPartAsStringFailsafe("parent", 36); + Album parent = webInterface.getCore().getAlbum(parentId, false); + Album album = webInterface.getCore().createAlbum(currentSone, parent); + album.setName(name); + throw new RedirectException("imageBrowser.html?album=" + album.getId()); + } + } + +} diff --git a/src/main/java/net/pterodactylus/sone/web/ImageBrowserPage.java b/src/main/java/net/pterodactylus/sone/web/ImageBrowserPage.java new file mode 100644 index 0000000..6da7cda --- /dev/null +++ b/src/main/java/net/pterodactylus/sone/web/ImageBrowserPage.java @@ -0,0 +1,68 @@ +/* + * Sone - ImageBrowserPage.java - Copyright © 2011 David Roden + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package net.pterodactylus.sone.web; + +import net.pterodactylus.sone.data.Album; +import net.pterodactylus.sone.data.Image; +import net.pterodactylus.util.template.Template; +import net.pterodactylus.util.template.TemplateContext; + +/** + * The image browser page is the entry page for the image management. + * + * @author David ‘Bombe’ Roden + */ +public class ImageBrowserPage extends SoneTemplatePage { + + /** + * Creates a new image browser page. + * + * @param template + * The template to render + * @param webInterface + * The Sone web interface + */ + public ImageBrowserPage(Template template, WebInterface webInterface) { + super("imageBrowser.html", template, "Page.ImageBrowser.Title", webInterface, true); + } + + // + // SONETEMPLATEPAGE METHODS + // + + /** + * {@inheritDoc} + */ + @Override + protected void processTemplate(Request request, TemplateContext templateContext) throws RedirectException { + super.processTemplate(request, templateContext); + String albumId = request.getHttpRequest().getParam("album", null); + if (albumId != null) { + Album album = webInterface.getCore().getAlbum(albumId, false); + templateContext.set("albumRequested", true); + templateContext.set("album", album); + return; + } + String imageId = request.getHttpRequest().getParam("image", null); + if (imageId != null) { + Image image = webInterface.getCore().getImage(imageId, false); + templateContext.set("imageRequested", true); + templateContext.set("image", image); + } + } +} diff --git a/src/main/java/net/pterodactylus/sone/web/WebInterface.java b/src/main/java/net/pterodactylus/sone/web/WebInterface.java index 89cec92..e3a95d4 100644 --- a/src/main/java/net/pterodactylus/sone/web/WebInterface.java +++ b/src/main/java/net/pterodactylus/sone/web/WebInterface.java @@ -36,6 +36,7 @@ import java.util.logging.Logger; import net.pterodactylus.sone.core.Core; import net.pterodactylus.sone.core.CoreListener; +import net.pterodactylus.sone.data.Album; import net.pterodactylus.sone.data.Post; import net.pterodactylus.sone.data.Reply; import net.pterodactylus.sone.data.Sone; @@ -44,6 +45,7 @@ import net.pterodactylus.sone.freenet.wot.Identity; import net.pterodactylus.sone.freenet.wot.Trust; import net.pterodactylus.sone.main.SonePlugin; import net.pterodactylus.sone.notify.ListNotification; +import net.pterodactylus.sone.template.AlbumAccessor; import net.pterodactylus.sone.template.CollectionAccessor; import net.pterodactylus.sone.template.CssClassNameFilter; import net.pterodactylus.sone.template.GetPagePlugin; @@ -187,6 +189,7 @@ public class WebInterface implements CoreListener { templateContextFactory.addAccessor(Sone.class, new SoneAccessor(getCore())); templateContextFactory.addAccessor(Post.class, new PostAccessor(getCore())); templateContextFactory.addAccessor(Reply.class, new ReplyAccessor(getCore())); + templateContextFactory.addAccessor(Album.class, new AlbumAccessor()); templateContextFactory.addAccessor(Identity.class, new IdentityAccessor(getCore())); templateContextFactory.addAccessor(NotificationManager.class, new NotificationManagerAccessor()); templateContextFactory.addAccessor(Trust.class, new TrustAccessor()); @@ -531,6 +534,8 @@ public class WebInterface implements CoreListener { Template deletePostTemplate = TemplateParser.parse(createReader("/templates/deletePost.html")); Template deleteReplyTemplate = TemplateParser.parse(createReader("/templates/deleteReply.html")); Template deleteSoneTemplate = TemplateParser.parse(createReader("/templates/deleteSone.html")); + Template imageBrowserTemplate = TemplateParser.parse(createReader("/templates/imageBrowser.html")); + Template createAlbumTemplate = TemplateParser.parse(createReader("/templates/createAlbum.html")); Template noPermissionTemplate = TemplateParser.parse(createReader("/templates/noPermission.html")); Template optionsTemplate = TemplateParser.parse(createReader("/templates/options.html")); Template aboutTemplate = TemplateParser.parse(createReader("/templates/about.html")); @@ -557,6 +562,8 @@ public class WebInterface implements CoreListener { pageToadlets.add(pageToadletFactory.createPageToadlet(new UnlockSonePage(emptyTemplate, this))); pageToadlets.add(pageToadletFactory.createPageToadlet(new FollowSonePage(emptyTemplate, this))); pageToadlets.add(pageToadletFactory.createPageToadlet(new UnfollowSonePage(emptyTemplate, this))); + pageToadlets.add(pageToadletFactory.createPageToadlet(new ImageBrowserPage(imageBrowserTemplate, this), "ImageBrowser")); + pageToadlets.add(pageToadletFactory.createPageToadlet(new CreateAlbumPage(createAlbumTemplate, this))); pageToadlets.add(pageToadletFactory.createPageToadlet(new TrustPage(emptyTemplate, this))); pageToadlets.add(pageToadletFactory.createPageToadlet(new DistrustPage(emptyTemplate, this))); pageToadlets.add(pageToadletFactory.createPageToadlet(new UntrustPage(emptyTemplate, this))); diff --git a/src/main/resources/i18n/sone.en.properties b/src/main/resources/i18n/sone.en.properties index 9b48cad..3f64f51 100644 --- a/src/main/resources/i18n/sone.en.properties +++ b/src/main/resources/i18n/sone.en.properties @@ -12,6 +12,8 @@ Navigation.Menu.Item.Bookmarks.Name=Bookmarks Navigation.Menu.Item.Bookmarks.Tooltip=Show bookmarked posts Navigation.Menu.Item.EditProfile.Name=Edit Profile Navigation.Menu.Item.EditProfile.Tooltip=Edit the Profile of your Sone +Navigation.Menu.Item.ImageBrowser.Name=Images +Navigation.Menu.Item.ImageBrowser.Tooltip=Manages your Images Navigation.Menu.Item.DeleteSone.Name=Delete Sone Navigation.Menu.Item.DeleteSone.Tooltip=Deletes the current Sone Navigation.Menu.Item.Logout.Name=Logout @@ -154,6 +156,15 @@ Page.FollowSone.Title=Follow Sone - Sone Page.UnfollowSone.Title=Unfollow Sone - Sone +Page.ImageBrowser.Title=Image Browser - Sone +Page.ImageBrowser.Page.Title=Image Browser +Page.ImageBrowser.Album.Error.NotFound.Text=The requested album could not be found. It is possible that it has not yet been downloaded, or that it has been deleted. +Page.ImageBrowser.CreateAlbum.Button.CreateAlbum=Create Album + +Page.CreateAlbum.Title=Create Album - Sone +Page.CreateAlbum.Page.Title=Create Album +Page.CreateAlbum.Error.NameMissing=You seem to have forgotten to enter a name for your new album. + Page.Trust.Title=Trust Sone - Sone Page.Distrust.Title=Distrust Sone - Sone @@ -221,6 +232,9 @@ View.Trust.Tooltip.Trust=Trust this person View.Trust.Tooltip.Distrust=Assign negative trust to this person View.Trust.Tooltip.Untrust=Remove your trust assignment for this person +View.CreateAlbum.Title=Create Album +View.CreateAlbum.Label.Name=Name: + WebInterface.DefaultText.StatusUpdate=What’s on your mind? WebInterface.DefaultText.Message=Write a Message… WebInterface.DefaultText.Reply=Write a Reply… diff --git a/src/main/resources/static/javascript/sone.js b/src/main/resources/static/javascript/sone.js index 9ef6812..b6b1257 100644 --- a/src/main/resources/static/javascript/sone.js +++ b/src/main/resources/static/javascript/sone.js @@ -1342,6 +1342,13 @@ $(document).ready(function() { }); }); + /* ajaxify album creation input field. */ + getTranslation("WebInterface.DefaultText.Reply", function(text) { + $("#create-album input[type=text]").each(function() { + registerInputTextareaSwap(this, text, "name", false, true); + }); + }); + /* Ajaxifies all posts. */ /* calling getTranslation here will cache the necessary values. */ getTranslation("WebInterface.Confirmation.DeletePostButton", function(text) { diff --git a/src/main/resources/templates/createAlbum.html b/src/main/resources/templates/createAlbum.html new file mode 100644 index 0000000..7df8103 --- /dev/null +++ b/src/main/resources/templates/createAlbum.html @@ -0,0 +1,11 @@ +<%include include/head.html> + +

<%= Page.CreateAlbum.Page.Title|l10n|html>

+ + <%if nameMissing> +

<%= Page.CreateAlbum.Error.NameMissing|l10n|html>

+ <%/if> + + <%include include/createAlbum.html> + +<%include include/tail.html> diff --git a/src/main/resources/templates/imageBrowser.html b/src/main/resources/templates/imageBrowser.html new file mode 100644 index 0000000..ca2014d --- /dev/null +++ b/src/main/resources/templates/imageBrowser.html @@ -0,0 +1,60 @@ +<%include include/head.html> + + + +

<%= Page.ImageBrowser.Page.Title|l10n|html>

+ + <%if albumRequested> + + <%ifnull album> + +

<%= Page.ImageBrowser.Album.Error.NotFound.Text|l10n|html>

+ + <%elseifnull album.name> + +

<%= Page.ImageBrowser.Album.Error.NotFound.Text|l10n|html>

+ + <%else> + +

<% album.name|html>

+ + + + <%foreach album.albums album> +
+
<% album.name|html>
+
+ <%/foreach> + + <%include include/createAlbum.html> + +
+ <% album.description|html> +
+ + <%/if> + + <%elseif imageRequested> + + <%else> + + <%foreach currentSone.albums album> +
+
<% album.name|html>
+
+ <%/foreach> + + <%include include/createAlbum.html> + + <%/if> + +<%include include/tail.html> diff --git a/src/main/resources/templates/include/createAlbum.html b/src/main/resources/templates/include/createAlbum.html new file mode 100644 index 0000000..6e3623f --- /dev/null +++ b/src/main/resources/templates/include/createAlbum.html @@ -0,0 +1,9 @@ +

<%= View.CreateAlbum.Title|l10n|html>

+ +
+ + + + + +
diff --git a/src/main/resources/templates/insert/include/album.xml b/src/main/resources/templates/insert/include/album.xml new file mode 100644 index 0000000..cd845da --- /dev/null +++ b/src/main/resources/templates/insert/include/album.xml @@ -0,0 +1,23 @@ + + <% album.id|xml> + <% album.name|xml> + <% album.description|xml> + + <%foreach album.albums album> + <%include insert/include/album.xml> + <%/foreach> + + + <%foreach album.images image> + + <% image.id|xml> + <% image.creationTime|xml> + <% image.key|xml> + <% image.width|xml> + <% image.height|xml> + <% image.title|xml> + <% image.description|xml> + + <%/foreach> + + diff --git a/src/main/resources/templates/insert/sone.xml b/src/main/resources/templates/insert/sone.xml index e25cac9..69f647d 100644 --- a/src/main/resources/templates/insert/sone.xml +++ b/src/main/resources/templates/insert/sone.xml @@ -60,4 +60,10 @@ <%/foreach> + + <%foreach currentSone.albums album> + <%include insert/include/album.xml> + <%/foreach> + +