From 6b65a32a69b0e3721c58b4501a6b58fa4989f162 Mon Sep 17 00:00:00 2001 From: =?utf8?q?David=20=E2=80=98Bombe=E2=80=99=20Roden?= Date: Fri, 24 Jul 2015 06:25:34 +0200 Subject: [PATCH] Change album ID to be unique, add internal ID --- .../java/net/pterodactylus/sone/core/Core.java | 4 +-- .../java/net/pterodactylus/sone/data/Album.java | 1 + .../net/pterodactylus/sone/data/IdBuilder.java | 31 ++++++++++++++++++++++ .../pterodactylus/sone/data/impl/AlbumImpl.java | 8 ++++++ .../pterodactylus/sone/web/CreateAlbumPage.java | 3 ++- .../pterodactylus/sone/web/DeleteAlbumPage.java | 3 ++- .../net/pterodactylus/sone/web/EditAlbumPage.java | 3 ++- .../pterodactylus/sone/web/UploadImagePage.java | 3 ++- src/main/resources/templates/insert/sone.xml | 4 +-- .../net/pterodactylus/sone/data/IdBuilderTest.java | 26 ++++++++++++++++++ .../sone/database/memory/MemoryDatabaseTest.java | 2 +- 11 files changed, 79 insertions(+), 9 deletions(-) create mode 100644 src/main/java/net/pterodactylus/sone/data/IdBuilder.java create mode 100644 src/test/java/net/pterodactylus/sone/data/IdBuilderTest.java diff --git a/src/main/java/net/pterodactylus/sone/core/Core.java b/src/main/java/net/pterodactylus/sone/core/Core.java index da209d8..8e00e23 100644 --- a/src/main/java/net/pterodactylus/sone/core/Core.java +++ b/src/main/java/net/pterodactylus/sone/core/Core.java @@ -1514,7 +1514,7 @@ public class Core extends AbstractService implements SoneProvider, PostProvider, int albumCounter = 0; for (Album album : albums) { String albumPrefix = sonePrefix + "/Albums/" + albumCounter++; - configuration.getStringValue(albumPrefix + "/ID").setValue(album.getId()); + configuration.getStringValue(albumPrefix + "/ID").setValue(album.getInternalId()); configuration.getStringValue(albumPrefix + "/Title").setValue(album.getTitle()); configuration.getStringValue(albumPrefix + "/Description").setValue(album.getDescription()); configuration.getStringValue(albumPrefix + "/Parent").setValue(album.getParent().equals(sone.getRootAlbum()) ? null : album.getParent().getId()); @@ -1531,7 +1531,7 @@ public class Core extends AbstractService implements SoneProvider, PostProvider, } String imagePrefix = sonePrefix + "/Images/" + imageCounter++; configuration.getStringValue(imagePrefix + "/ID").setValue(image.getId()); - configuration.getStringValue(imagePrefix + "/Album").setValue(album.getId()); + configuration.getStringValue(imagePrefix + "/Album").setValue(album.getInternalId()); configuration.getStringValue(imagePrefix + "/Key").setValue(image.getKey()); configuration.getStringValue(imagePrefix + "/Title").setValue(image.getTitle()); configuration.getStringValue(imagePrefix + "/Description").setValue(image.getDescription()); diff --git a/src/main/java/net/pterodactylus/sone/data/Album.java b/src/main/java/net/pterodactylus/sone/data/Album.java index c75088f..b4c6b0f 100644 --- a/src/main/java/net/pterodactylus/sone/data/Album.java +++ b/src/main/java/net/pterodactylus/sone/data/Album.java @@ -107,6 +107,7 @@ public interface Album extends Identified, Fingerprintable { * @return The ID of this album */ String getId(); + String getInternalId(); /** * Returns the Sone this album belongs to. diff --git a/src/main/java/net/pterodactylus/sone/data/IdBuilder.java b/src/main/java/net/pterodactylus/sone/data/IdBuilder.java new file mode 100644 index 0000000..f9accc1 --- /dev/null +++ b/src/main/java/net/pterodactylus/sone/data/IdBuilder.java @@ -0,0 +1,31 @@ +package net.pterodactylus.sone.data; + +import javax.annotation.Nonnull; +import javax.annotation.concurrent.ThreadSafe; + +import com.google.common.base.Charsets; +import com.google.common.hash.HashFunction; +import com.google.common.hash.Hashing; + +/** + * Builds (practically) unique IDs by combining Sone and element IDs. + * + * @author David ‘Bombe’ Roden + */ +@ThreadSafe +public class IdBuilder { + + private static final HashFunction HASH_FUNCTION = Hashing.sha256(); + public static final int ID_STRING_LENGTH = HASH_FUNCTION.bits() / 4; + + private final HashFunction sha256 = HASH_FUNCTION; + + @Nonnull + public String buildId(@Nonnull String soneId, @Nonnull String id) { + return sha256.newHasher() + .putBytes(soneId.getBytes(Charsets.UTF_8)) + .putBytes(id.getBytes(Charsets.UTF_8)) + .hash().toString(); + } + +} diff --git a/src/main/java/net/pterodactylus/sone/data/impl/AlbumImpl.java b/src/main/java/net/pterodactylus/sone/data/impl/AlbumImpl.java index 3488577..6a45187 100644 --- a/src/main/java/net/pterodactylus/sone/data/impl/AlbumImpl.java +++ b/src/main/java/net/pterodactylus/sone/data/impl/AlbumImpl.java @@ -29,6 +29,7 @@ import java.util.Map; 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; @@ -46,6 +47,8 @@ import com.google.common.hash.Hashing; */ public class AlbumImpl implements Album { + private final IdBuilder idBuilder = new IdBuilder(); + /** The ID of this album. */ private final String id; @@ -95,6 +98,11 @@ public class AlbumImpl implements Album { @Override public String getId() { + return idBuilder.buildId(sone.getId(), id); + } + + @Override + public String getInternalId() { return id; } diff --git a/src/main/java/net/pterodactylus/sone/web/CreateAlbumPage.java b/src/main/java/net/pterodactylus/sone/web/CreateAlbumPage.java index 1c599e4..e0f0725 100644 --- a/src/main/java/net/pterodactylus/sone/web/CreateAlbumPage.java +++ b/src/main/java/net/pterodactylus/sone/web/CreateAlbumPage.java @@ -19,6 +19,7 @@ package net.pterodactylus.sone.web; import net.pterodactylus.sone.data.Album; import net.pterodactylus.sone.data.Album.Modifier.AlbumTitleMustNotBeEmpty; +import net.pterodactylus.sone.data.IdBuilder; import net.pterodactylus.sone.data.Sone; import net.pterodactylus.sone.text.TextFilter; import net.pterodactylus.sone.web.page.FreenetRequest; @@ -63,7 +64,7 @@ public class CreateAlbumPage extends SoneTemplatePage { } String description = request.getHttpRequest().getPartAsStringFailsafe("description", 256).trim(); Sone currentSone = getCurrentSone(request.getToadletContext()); - String parentId = request.getHttpRequest().getPartAsStringFailsafe("parent", 36); + String parentId = request.getHttpRequest().getPartAsStringFailsafe("parent", IdBuilder.ID_STRING_LENGTH); Album parent = webInterface.getCore().getAlbum(parentId); if (parentId.equals("")) { parent = currentSone.getRootAlbum(); diff --git a/src/main/java/net/pterodactylus/sone/web/DeleteAlbumPage.java b/src/main/java/net/pterodactylus/sone/web/DeleteAlbumPage.java index 98e8909..e588976 100644 --- a/src/main/java/net/pterodactylus/sone/web/DeleteAlbumPage.java +++ b/src/main/java/net/pterodactylus/sone/web/DeleteAlbumPage.java @@ -18,6 +18,7 @@ package net.pterodactylus.sone.web; import net.pterodactylus.sone.data.Album; +import net.pterodactylus.sone.data.IdBuilder; import net.pterodactylus.sone.web.page.FreenetRequest; import net.pterodactylus.util.template.Template; import net.pterodactylus.util.template.TemplateContext; @@ -49,7 +50,7 @@ public class DeleteAlbumPage extends SoneTemplatePage { protected void processTemplate(FreenetRequest request, TemplateContext templateContext) throws RedirectException { super.processTemplate(request, templateContext); if (request.getMethod() == Method.POST) { - String albumId = request.getHttpRequest().getPartAsStringFailsafe("album", 36); + String albumId = request.getHttpRequest().getPartAsStringFailsafe("album", IdBuilder.ID_STRING_LENGTH); Album album = webInterface.getCore().getAlbum(albumId); if (album == null) { throw new RedirectException("invalid.html"); diff --git a/src/main/java/net/pterodactylus/sone/web/EditAlbumPage.java b/src/main/java/net/pterodactylus/sone/web/EditAlbumPage.java index 66434e5..eca15de 100644 --- a/src/main/java/net/pterodactylus/sone/web/EditAlbumPage.java +++ b/src/main/java/net/pterodactylus/sone/web/EditAlbumPage.java @@ -19,6 +19,7 @@ package net.pterodactylus.sone.web; import net.pterodactylus.sone.data.Album; import net.pterodactylus.sone.data.Album.Modifier.AlbumTitleMustNotBeEmpty; +import net.pterodactylus.sone.data.IdBuilder; import net.pterodactylus.sone.text.TextFilter; import net.pterodactylus.sone.web.page.FreenetRequest; import net.pterodactylus.util.template.Template; @@ -51,7 +52,7 @@ public class EditAlbumPage extends SoneTemplatePage { protected void processTemplate(FreenetRequest request, TemplateContext templateContext) throws RedirectException { super.processTemplate(request, templateContext); if (request.getMethod() == Method.POST) { - String albumId = request.getHttpRequest().getPartAsStringFailsafe("album", 36); + String albumId = request.getHttpRequest().getPartAsStringFailsafe("album", IdBuilder.ID_STRING_LENGTH); Album album = webInterface.getCore().getAlbum(albumId); if (album == null) { throw new RedirectException("invalid.html"); diff --git a/src/main/java/net/pterodactylus/sone/web/UploadImagePage.java b/src/main/java/net/pterodactylus/sone/web/UploadImagePage.java index a1e987a..2c7b0a9 100644 --- a/src/main/java/net/pterodactylus/sone/web/UploadImagePage.java +++ b/src/main/java/net/pterodactylus/sone/web/UploadImagePage.java @@ -34,6 +34,7 @@ import javax.imageio.ImageReader; import javax.imageio.stream.ImageInputStream; import net.pterodactylus.sone.data.Album; +import net.pterodactylus.sone.data.IdBuilder; import net.pterodactylus.sone.data.Image.Modifier.ImageTitleMustNotBeEmpty; import net.pterodactylus.sone.data.Sone; import net.pterodactylus.sone.data.TemporaryImage; @@ -83,7 +84,7 @@ public class UploadImagePage extends SoneTemplatePage { super.processTemplate(request, templateContext); if (request.getMethod() == Method.POST) { Sone currentSone = getCurrentSone(request.getToadletContext()); - String parentId = request.getHttpRequest().getPartAsStringFailsafe("parent", 36); + String parentId = request.getHttpRequest().getPartAsStringFailsafe("parent", IdBuilder.ID_STRING_LENGTH); Album parent = webInterface.getCore().getAlbum(parentId); if (parent == null) { throw new RedirectException("noPermission.html"); diff --git a/src/main/resources/templates/insert/sone.xml b/src/main/resources/templates/insert/sone.xml index 3d456d4..747ad51 100644 --- a/src/main/resources/templates/insert/sone.xml +++ b/src/main/resources/templates/insert/sone.xml @@ -66,9 +66,9 @@ <%/first> - <%album.id|xml> + <%album.internalId|xml> <%if !album.parent.root> - <%album.parent.id|xml> + <%album.parent.internalId|xml> <%/if> <%album.title|xml> <%album.description|xml> diff --git a/src/test/java/net/pterodactylus/sone/data/IdBuilderTest.java b/src/test/java/net/pterodactylus/sone/data/IdBuilderTest.java new file mode 100644 index 0000000..bc8da11 --- /dev/null +++ b/src/test/java/net/pterodactylus/sone/data/IdBuilderTest.java @@ -0,0 +1,26 @@ +package net.pterodactylus.sone.data; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; + +import org.junit.Test; + +/** + * Unit test for {@link IdBuilderTest}. + * + * @author David ‘Bombe’ Roden + */ +public class IdBuilderTest { + + private static final String SONE_ID = "~Yp72VX0c6FLDvgIzip5wIvaGIIrjKcKvnX~pTaMKXs"; + private static final String ELEMENT_ID = "88CC70AE-E853-4EEE-B245-E4C55F40DDDF"; + private static final String EXPECTED_ID = "139a629a13f6a2c4191fb19ecead7e57335ea3deb2a971b88d5e004378c4daad"; + + private final IdBuilder idBuilder = new IdBuilder(); + + @Test + public void idBuilderBuildsCorrectIds() { + assertThat(idBuilder.buildId(SONE_ID, ELEMENT_ID), is(EXPECTED_ID)); + } + +} diff --git a/src/test/java/net/pterodactylus/sone/database/memory/MemoryDatabaseTest.java b/src/test/java/net/pterodactylus/sone/database/memory/MemoryDatabaseTest.java index cc5babb..c00f25a 100644 --- a/src/test/java/net/pterodactylus/sone/database/memory/MemoryDatabaseTest.java +++ b/src/test/java/net/pterodactylus/sone/database/memory/MemoryDatabaseTest.java @@ -268,7 +268,7 @@ public class MemoryDatabaseTest { @Test public void testBasicAlbumFunctionality() { - Album newAlbum = new AlbumImpl(mock(Sone.class)); + Album newAlbum = new AlbumImpl(when(mock(Sone.class).getId()).thenReturn(SONE_ID).getMock()); assertThat(memoryDatabase.getAlbum(newAlbum.getId()), is(Optional.absent())); memoryDatabase.storeAlbum(newAlbum); assertThat(memoryDatabase.getAlbum(newAlbum.getId()), is(of(newAlbum))); -- 2.7.4