.setHeight(height)
.update();
album.addImage(image);
- images.put(image.getId(), image);
+ images.put(imageId, image);
}
}
continue;
}
String imagePrefix = sonePrefix + "/Images/" + imageCounter++;
- configuration.getStringValue(imagePrefix + "/ID").setValue(image.getId());
+ configuration.getStringValue(imagePrefix + "/ID").setValue(image.getInternalId());
configuration.getStringValue(imagePrefix + "/Album").setValue(album.getInternalId());
configuration.getStringValue(imagePrefix + "/Key").setValue(image.getKey());
configuration.getStringValue(imagePrefix + "/Title").setValue(image.getTitle());
* @return The ID of this image
*/
String getId();
+ String getInternalId();
/**
* Returns the Sone this image belongs to.
return this;
}
checkArgument(avatar.getSone().equals(sone), "avatar must belong to Sone");
- this.avatar = avatar.getId();
+ this.avatar = avatar.getInternalId();
return this;
}
import net.pterodactylus.sone.freenet.wot.OwnIdentity;
import net.pterodactylus.sone.template.SoneAccessor;
+import com.google.common.base.Optional;
import freenet.keys.FreenetURI;
import com.google.common.base.Function;
* @return The root album of this Sone
*/
Album getRootAlbum();
+ Optional<Image> getImageByInternalId(final String internalId);
/**
* Returns Sone-specific options.
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.PostReply;
import net.pterodactylus.sone.data.Profile;
import net.pterodactylus.sone.data.SoneOptions;
import net.pterodactylus.sone.freenet.wot.Identity;
+import com.google.common.base.Optional;
import freenet.keys.FreenetURI;
import com.google.common.base.Objects;
}
@Override
+ public Optional<Image> getImageByInternalId(String internalId) {
+ return Optional.absent();
+ }
+
+ @Override
public SoneOptions getOptions() {
return null;
}
import java.util.UUID;
import net.pterodactylus.sone.data.Album;
+import net.pterodactylus.sone.data.IdBuilder;
import net.pterodactylus.sone.data.Image;
import net.pterodactylus.sone.data.Sone;
*/
public class ImageImpl implements Image {
+ private final IdBuilder idBuilder = new IdBuilder();
+
/** The ID of the image. */
private final String id;
@Override
public String getId() {
+ return idBuilder.buildId(sone.getId(), id);
+ }
+
+ @Override
+ public String getInternalId() {
return id;
}
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.logging.Level;
import java.util.logging.Logger;
+import javax.annotation.Nullable;
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.PostReply;
import net.pterodactylus.sone.data.Profile;
import net.pterodactylus.sone.freenet.wot.Identity;
import net.pterodactylus.sone.freenet.wot.OwnIdentity;
+import com.google.common.base.Optional;
+import com.google.common.base.Predicate;
+import com.google.common.collect.FluentIterable;
import freenet.keys.FreenetURI;
import com.google.common.hash.Hasher;
return rootAlbum;
}
+ @Override
+ public Optional<Image> getImageByInternalId(final String internalId) {
+ return FluentIterable.from(toAllImages.apply(this)).filter(new Predicate<Image>() {
+ @Override
+ public boolean apply(@Nullable Image input) {
+ return (input != null) && input.getInternalId().equals(internalId);
+ }
+ }).first();
+ }
+
/**
* Returns Sone-specific options.
*
--- /dev/null
+package net.pterodactylus.sone.template;
+
+import java.util.Map;
+
+import javax.annotation.Nullable;
+
+import net.pterodactylus.sone.data.IdBuilder;
+import net.pterodactylus.sone.data.Sone;
+import net.pterodactylus.util.template.Filter;
+import net.pterodactylus.util.template.TemplateContext;
+
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+
+/**
+ * Filter that {@link IdBuilder builds IDs} from a piped-in element ID and a Sone or Sone ID given as parameter “sone.”
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class BuildIdFilter implements Filter {
+
+ private final IdBuilder idBuilder = new IdBuilder();
+
+ @Override
+ public Object format(TemplateContext templateContext, Object data, Map<String, Object> parameters) {
+ Optional<String> soneId = getSoneId(parameters);
+ if (!soneId.isPresent()) {
+ return null;
+ }
+ Optional<String> elementId = Optional.fromNullable(data).transform(getStringValue());
+ if (!elementId.isPresent()) {
+ return null;
+ }
+ return idBuilder.buildId(soneId.get(), elementId.get());
+ }
+
+ private Optional<String> getSoneId(Map<String, Object> parameters) {
+ Object soneObject = parameters.get("sone");
+ if (soneObject instanceof String) {
+ return Optional.of((String) soneObject);
+ } else if (soneObject instanceof Sone) {
+ return Optional.of(((Sone) soneObject).getId());
+ }
+ return Optional.absent();
+ }
+
+ private Function<? super Object, String> getStringValue() {
+ return new Function<Object, String>() {
+ @Nullable
+ @Override
+ public String apply(Object input) {
+ return (input != null) ? input.toString() : null;
+ }
+ };
+ }
+
+}
if (avatarId == null) {
return null;
}
- if (core.getImage(avatarId, false) == null) {
+ if (!currentSone.getImageByInternalId(avatarId).isPresent()) {
/* avatar ID but no matching image? show nothing. */
return null;
}
package net.pterodactylus.sone.web;
+import net.pterodactylus.sone.data.IdBuilder;
import net.pterodactylus.sone.data.Image;
import net.pterodactylus.sone.web.page.FreenetRequest;
import net.pterodactylus.util.template.Template;
@Override
protected void processTemplate(FreenetRequest request, TemplateContext templateContext) throws RedirectException {
super.processTemplate(request, templateContext);
- String imageId = (request.getMethod() == Method.POST) ? request.getHttpRequest().getPartAsStringFailsafe("image", 36) : request.getHttpRequest().getParam("image");
+ String imageId = (request.getMethod() == Method.POST) ? request.getHttpRequest().getPartAsStringFailsafe("image", IdBuilder.ID_STRING_LENGTH)
+ : request.getHttpRequest().getParam("image");
Image image = webInterface.getCore().getImage(imageId, false);
if (image == null) {
throw new RedirectException("invalid.html");
webInterface.getCore().touchConfiguration();
throw new RedirectException("imageBrowser.html?album=" + album.getParent().getId());
}
- String albumImageId = request.getHttpRequest().getPartAsStringFailsafe("album-image", 36);
+ String albumImageId = request.getHttpRequest().getPartAsStringFailsafe("album-image", IdBuilder.ID_STRING_LENGTH);
if (webInterface.getCore().getImage(albumImageId, false) == null) {
albumImageId = null;
}
package net.pterodactylus.sone.web;
+import net.pterodactylus.sone.data.IdBuilder;
import net.pterodactylus.sone.data.Image;
import net.pterodactylus.sone.text.TextFilter;
import net.pterodactylus.sone.web.page.FreenetRequest;
protected void processTemplate(FreenetRequest request, TemplateContext templateContext) throws RedirectException {
super.processTemplate(request, templateContext);
if (request.getMethod() == Method.POST) {
- String imageId = request.getHttpRequest().getPartAsStringFailsafe("image", 36);
+ String imageId = request.getHttpRequest().getPartAsStringFailsafe("image", IdBuilder.ID_STRING_LENGTH);
String returnPage = request.getHttpRequest().getPartAsStringFailsafe("returnPage", 256);
Image image = webInterface.getCore().getImage(imageId, false);
if (image == null) {
import java.util.List;
+import net.pterodactylus.sone.data.IdBuilder;
import net.pterodactylus.sone.data.Profile;
import net.pterodactylus.sone.data.Profile.DuplicateField;
import net.pterodactylus.sone.data.Profile.Field;
birthDay = parseInt(request.getHttpRequest().getPartAsStringFailsafe("birth-day", 256).trim(), null);
birthMonth = parseInt(request.getHttpRequest().getPartAsStringFailsafe("birth-month", 256).trim(), null);
birthYear = parseInt(request.getHttpRequest().getPartAsStringFailsafe("birth-year", 256).trim(), null);
- avatarId = request.getHttpRequest().getPartAsStringFailsafe("avatarId", 36);
+ avatarId = request.getHttpRequest().getPartAsStringFailsafe("avatarId", IdBuilder.ID_STRING_LENGTH);
profile.setFirstName(firstName.length() > 0 ? firstName : null);
profile.setMiddleName(middleName.length() > 0 ? middleName : null);
profile.setLastName(lastName.length() > 0 ? lastName : null);
profile.setBirthDay(birthDay).setBirthMonth(birthMonth).setBirthYear(birthYear);
- profile.setAvatar(webInterface.getCore().getImage(avatarId, false));
+ profile.setAvatar(currentSone.getImageByInternalId(avatarId).orNull());
for (Field field : fields) {
String value = request.getHttpRequest().getPartAsStringFailsafe("field-" + field.getId(), 400);
String filteredValue = filter(request.getHttpRequest().getHeader("Host"), value);
import net.pterodactylus.sone.main.SonePlugin;
import net.pterodactylus.sone.notify.ListNotification;
import net.pterodactylus.sone.template.AlbumAccessor;
+import net.pterodactylus.sone.template.BuildIdFilter;
import net.pterodactylus.sone.template.CollectionAccessor;
import net.pterodactylus.sone.template.CssClassNameFilter;
import net.pterodactylus.sone.template.HttpRequestAccessor;
templateContextFactory.addFilter("unique", new UniqueElementFilter());
templateContextFactory.addFilter("mod", new ModFilter());
templateContextFactory.addFilter("paginate", new PaginationFilter());
+ templateContextFactory.addFilter("build-id", new BuildIdFilter());
templateContextFactory.addProvider(TemplateProvider.TEMPLATE_CONTEXT_PROVIDER);
templateContextFactory.addProvider(new ClassPathTemplateProvider(WebInterface.class, "/templates/"));
templateContextFactory.addTemplateObject("webInterface", this);
</li>
<%foreach currentSone.allImages image>
<li>
- <input type="radio" name="avatarId" value="<%image.id|html>"<%if avatarId|match value=image.id> checked="checked"<%/if>/>
+ <input type="radio" name="avatarId" value="<%image.internalId|html>"<%if avatarId|match value=image.internalId> checked="checked"<%/if>/>
<div class="post-avatar"><% image|image-link max-width==48 max-height==48 mode==enlarge title=image.title></div>
</li>
<%/foreach>
<a class="picture" href="index.html">
<%ifnull !currentSone>
<%ifnull !currentSone.profile.avatar>
- <%currentSone.profile.avatar|image-link max-width==80 max-height==80 mode==enlarge title=="Profile Avatar">
+ <%currentSone.profile.avatar|build-id sone=currentSone|image-link max-width==80 max-height==80 mode==enlarge title=="Profile Avatar">
<%else>
<img src="/WebOfTrust/GetIdenticon?identity=<% currentSone.id|html>&width=80&height=80" width="80" height="80" alt="Profile Avatar" />
<%/if>
<div class="sone-menu-id hidden"><%sone.id|html></div>
<div class="avatar menu-avatar">
<%ifnull !sone.profile.avatar>
- <%sone.profile.avatar|image-link max-width==64 max-height==64 mode==enlarge title=sone.niceName>
+ <%sone.profile.avatar|build-id sone=sone|image-link max-width==64 max-height==64 mode==enlarge title=sone.niceName>
<%else>
<img src="/WebOfTrust/GetIdenticon?identity=<%sone.id|html>&width=128&height=128" width="64" height="64" alt="Avatar Image" />
<%/if>
<div class="avatar post-avatar" >
<%if post.loaded>
<%ifnull !post.sone.profile.avatar>
- <%post.sone.profile.avatar|image-link max-width==48 max-height==48 mode==enlarge title=="Avatar Image">
+ <%post.sone.profile.avatar|build-id sone=post.sone|image-link max-width==48 max-height==48 mode==enlarge title=="Avatar Image">
<%else>
<img src="/WebOfTrust/GetIdenticon?identity=<% post.sone.id|html>&width=96&height=96" width="48" height="48" alt="Avatar Image" />
<%/if>
<%include include/soneMenu.html class=="sone-reply-menu" sone=reply.sone>
<div class="avatar reply-avatar">
<%ifnull !reply.sone.profile.avatar>
- <% reply.sone.profile.avatar|image-link max-width==36 max-height==36 mode==enlarge title=="Avatar Image">
+ <% reply.sone.profile.avatar|build-id sone=reply.sone|image-link max-width==36 max-height==36 mode==enlarge title=="Avatar Image">
<%else>
<img src="/WebOfTrust/GetIdenticon?identity=<% reply.sone.id|html>&width=72&height=72" width="36" height="36" alt="Avatar Image" />
<%/if>
<%/if>
<title><%album.title|xml></title>
<description><%album.description|xml></description>
- <album-image><%album.albumImage.id|xml></album-image>
+ <album-image><%album.albumImage.internalId|xml></album-image>
<%foreach album.images image>
<%first>
<images>
<%/first>
<image>
- <id><%image.id|xml></id>
+ <id><%image.internalId|xml></id>
<creation-time><%image.creationTime|xml></creation-time>
<key><%image.key|xml></key>
<title><%image.title|xml></title>
byte[] imageData = new byte[] { 1, 2, 3, 4 };
temporaryImage.setImageData(imageData);
Image image = new ImageImpl("image-id");
+ image.modify().setSone(sone).update();
InsertToken insertToken = freenetInterface.new InsertToken(image);
InsertContext insertContext = mock(InsertContext.class);
when(highLevelSimpleClient.getInsertContext(anyBoolean())).thenReturn(insertContext);
byte[] imageData = new byte[] { 1, 2, 3, 4 };
temporaryImage.setImageData(imageData);
Image image = new ImageImpl("image-id");
+ image.modify().setSone(sone).update();
InsertToken insertToken = freenetInterface.new InsertToken(image);
InsertContext insertContext = mock(InsertContext.class);
when(highLevelSimpleClient.getInsertContext(anyBoolean())).thenReturn(insertContext);
import net.pterodactylus.sone.data.Album;
import net.pterodactylus.sone.data.Album.Modifier;
import net.pterodactylus.sone.data.Client;
+import net.pterodactylus.sone.data.IdBuilder;
import net.pterodactylus.sone.data.Image;
import net.pterodactylus.sone.data.Post;
import net.pterodactylus.sone.data.PostReply;
when(imageBuilder.withId(anyString())).thenAnswer(new Answer<ImageBuilder>() {
@Override
public ImageBuilder answer(InvocationOnMock invocation) {
- when(image.getId()).thenReturn(
- (String) invocation.getArguments()[0]);
+ when(image.getId()).thenReturn(new IdBuilder().buildId("identity", (String) invocation.getArguments()[0]));
+ when(image.getInternalId()).thenReturn((String) invocation.getArguments()[0]);
return imageBuilder;
}
});
assertThat(sone.getRootAlbum().getAlbums(), hasSize(1));
assertThat(sone.getRootAlbum().getAlbums().get(0).getImages(), hasSize(1));
Image image = sone.getRootAlbum().getAlbums().get(0).getImages().get(0);
- assertThat(image.getId(), is("image-id"));
+ assertThat(image.getId(), is(new IdBuilder().buildId("identity", "image-id")));
+ assertThat(image.getInternalId(), is("image-id"));
assertThat(image.getCreationTime(), is(1407197508000L));
assertThat(image.getKey(), is("KSK@GPLv3.txt"));
assertThat(image.getTitle(), is("image-title"));
--- /dev/null
+package net.pterodactylus.sone.template;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.nullValue;
+import static org.mockito.Mockito.when;
+
+import net.pterodactylus.sone.data.Sone;
+import net.pterodactylus.util.template.TemplateContext;
+
+import com.google.common.collect.ImmutableMap;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+/**
+ * Unit test for {@link BuildIdFilter}.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class BuildIdFilterTest {
+
+ private static final String SONE_ID = "~Yp72VX0c6FLDvgIzip5wIvaGIIrjKcKvnX~pTaMKXs";
+ private static final String ELEMENT_ID = "88CC70AE-E853-4EEE-B245-E4C55F40DDDF";
+ private static final Object EXPECTED_ID = "139a629a13f6a2c4191fb19ecead7e57335ea3deb2a971b88d5e004378c4daad";
+
+ private final BuildIdFilter buildIdFilter = new BuildIdFilter();
+ private final TemplateContext templateContext = null;
+
+ @Test
+ public void filterBuildsCorrectIdsWithSoneAsString() {
+ assertThat(buildIdFilter.format(templateContext, ELEMENT_ID, ImmutableMap.<String, Object>of("sone", SONE_ID)), is(EXPECTED_ID));
+ }
+
+ @Test
+ public void filterBuildsCorrectIdsWithSoneAsSone() {
+ Sone sone = Mockito.mock(Sone.class);
+ when(sone.getId()).thenReturn(SONE_ID);
+ assertThat(buildIdFilter.format(templateContext, ELEMENT_ID, ImmutableMap.<String, Object>of("sone", sone)), is(EXPECTED_ID));
+ }
+
+ @Test
+ public void filterReturnsNullIfSoneNotPresent() {
+ assertThat(buildIdFilter.format(templateContext, ELEMENT_ID, ImmutableMap.<String, Object>of()), nullValue());
+ }
+
+ @Test
+ public void filterReturnsNullIfElementNotPresent() {
+ assertThat(buildIdFilter.format(templateContext, null, ImmutableMap.<String, Object>of("sone", SONE_ID)), nullValue());
+ }
+
+}