Merge from master
authorNiki Roo <niki@nikiroo.be>
Thu, 14 May 2020 10:09:51 +0000 (12:09 +0200)
committerNiki Roo <niki@nikiroo.be>
Thu, 14 May 2020 10:09:51 +0000 (12:09 +0200)
data/JsonIO.java
library/BasicLibrary.java
library/CacheLibrary.java
library/LocalLibrary.java
library/RemoteLibrary.java
library/RemoteLibraryServer.java
library/WebLibrary.java
library/WebLibraryServer.java
library/WebLibraryServerHtml.java
library/WebLibraryUrls.java

index 5157dca3156a2a88eada47cabaa080191d6bb2c1..beff342bea00abd1d002c00a09716438a667a182 100644 (file)
@@ -8,6 +8,7 @@ import org.json.JSONException;
 import org.json.JSONObject;
 
 import be.nikiroo.fanfix.data.Paragraph.ParagraphType;
+import be.nikiroo.utils.Progress;
 
 public class JsonIO {
        static public JSONObject toJson(MetaData meta) {
@@ -200,6 +201,36 @@ public class JsonIO {
                return para;
        }
 
+       // no children included
+       static public JSONObject toJson(Progress pg) {
+               if (pg == null) {
+                       return null;
+               }
+
+               JSONObject json = new JSONObject();
+
+               put(json, "", Progress.class.getName());
+               put(json, "name", pg.getName());
+               put(json, "min", pg.getMin());
+               put(json, "max", pg.getMax());
+               put(json, "progress", pg.getProgress());
+
+               return json;
+       }
+
+       // no children included
+       static public Progress toProgress(JSONObject json) {
+               if (json == null) {
+                       return null;
+               }
+
+               Progress pg = new Progress(getString(json, "name"),
+                               getInt(json, "min", 0), getInt(json, "max", 100));
+               pg.setProgress(getInt(json, "progress", 0));
+
+               return pg;
+       }
+
        static public List<String> toListString(JSONArray array) {
                if (array != null) {
                        List<String> values = new ArrayList<String>();
index af7920bf14efdde77dbd2bebe77489f505b6fa30..f6024eef85025eefc0f0df1ada0b02fd2c2b254a 100644 (file)
@@ -311,7 +311,7 @@ abstract public class BasicLibrary {
         * 
         * @return the next luid
         */
-       protected abstract int getNextId();
+       protected abstract String getNextId();
 
        /**
         * Delete the target {@link Story}.
@@ -741,7 +741,7 @@ abstract public class BasicLibrary {
                pg.setName("Saving story");
 
                if (luid == null || luid.isEmpty()) {
-                       meta.setLuid(String.format("%03d", getNextId()));
+                       meta.setLuid(getNextId());
                } else {
                        meta.setLuid(luid);
                }
index a3c3b5e3b7bb6f5a61962e8837158e28692feb56..e184c1bd6555e7d79547ab61ab774d92e5b608ff 100644 (file)
@@ -419,7 +419,7 @@ public class CacheLibrary extends BasicLibrary {
        // BasicLibrary:
 
        @Override
-       protected int getNextId() {
+       protected String getNextId() {
                throw new java.lang.InternalError("Should not have been called");
        }
 
index 6720972682939785226de86a201ef2c4c4c7d68f..7220a3951de137f99a4a11ecc7e5f5b119abb3c1 100644 (file)
@@ -20,10 +20,10 @@ import be.nikiroo.fanfix.output.BasicOutput;
 import be.nikiroo.fanfix.output.BasicOutput.OutputType;
 import be.nikiroo.fanfix.output.InfoCover;
 import be.nikiroo.fanfix.supported.InfoReader;
+import be.nikiroo.utils.HashUtils;
 import be.nikiroo.utils.IOUtils;
 import be.nikiroo.utils.Image;
 import be.nikiroo.utils.Progress;
-import be.nikiroo.utils.StringUtils;
 
 /**
  * This {@link BasicLibrary} will store the stories locally on disk.
@@ -168,11 +168,11 @@ public class LocalLibrary extends BasicLibrary {
        }
 
        @Override
-       protected int getNextId() {
+       protected String getNextId() {
                getStories(null); // make sure lastId is set
 
                synchronized (lock) {
-                       return ++lastId;
+                       return String.format("%03d", ++lastId);
                }
        }
 
@@ -553,7 +553,7 @@ public class LocalLibrary extends BasicLibrary {
         */
        private File getAuthorCoverFile(String author) {
                File aDir = new File(baseDir, "_AUTHORS");
-               String hash = StringUtils.getMd5Hash(author);
+               String hash = HashUtils.md5(author);
                String ext = Instance.getInstance().getConfig()
                                .getString(Config.FILE_FORMAT_IMAGE_FORMAT_COVER);
                return new File(aDir, hash + "." + ext.toLowerCase());
index 3a60e02c9ed6fc845193574f897c3bd9b0ecc60a..ad92800878f63e31587fa449a07c4618a971bc49 100644 (file)
@@ -485,7 +485,7 @@ public class RemoteLibrary extends BasicLibrary {
        // The following methods are only used by Save and Delete in BasicLibrary:
 
        @Override
-       protected int getNextId() {
+       protected String getNextId() {
                throw new java.lang.InternalError("Should not have been called");
        }
 
index e54f105d6bf9233c4f1c4383c948630b57b79555..59819bb948903a1893b9e9d2751f43ca8d3a66a5 100644 (file)
@@ -3,6 +3,7 @@ package be.nikiroo.fanfix.library;
 import java.io.IOException;
 import java.net.URL;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
@@ -578,12 +579,16 @@ public class RemoteLibraryServer extends ServerObject {
 
        private boolean isAllowed(MetaData meta, List<String> whitelist,
                        List<String> blacklist) {
-               if (!whitelist.isEmpty() && !whitelist.contains(meta.getSource())) {
-                       return false;
+               MetaResultList one = new MetaResultList(Arrays.asList(meta));
+               if (!whitelist.isEmpty()) {
+                       if (one.filter(whitelist, null, null).isEmpty()) {
+                               return false;
+                       }
                }
-
-               if (blacklist.contains(meta.getSource())) {
-                       return false;
+               if (!blacklist.isEmpty()) {
+                       if (!one.filter(blacklist, null, null).isEmpty()) {
+                               return false;
+                       }
                }
 
                return true;
index 8c71ff590b41b85bba46e715b0ea8328af383592..9d1c773aae698457d920b5094668eebb74605202 100644 (file)
@@ -103,14 +103,18 @@ public class WebLibrary extends BasicLibrary {
 
                this.host = host;
                this.port = port;
-
-               // TODO: not supported yet
-               this.rw = false;
        }
 
+       /**
+        * Return the version of the program running server-side.
+        * <p>
+        * Never returns NULL.
+        * 
+        * @return the version or an empty {@link Version} if not known
+        */
        public Version getVersion() {
                try {
-                       InputStream in = download(WebLibraryUrls.VERSION_URL);
+                       InputStream in = post(WebLibraryUrls.VERSION_URL);
                        try {
                                return new Version(IOUtils.readSmallStream(in));
                        } finally {
@@ -125,10 +129,10 @@ public class WebLibrary extends BasicLibrary {
        @Override
        public Status getStatus() {
                try {
-                       download(WebLibraryUrls.INDEX_URL).close();
+                       post(WebLibraryUrls.INDEX_URL).close();
                } catch (IOException e) {
                        try {
-                               download(WebLibraryUrls.VERSION_URL).close();
+                               post("/style.css").close();
                                return Status.UNAUTHORIZED;
                        } catch (IOException ioe) {
                                return Status.UNAVAILABLE;
@@ -146,7 +150,7 @@ public class WebLibrary extends BasicLibrary {
 
        @Override
        public Image getCover(String luid) throws IOException {
-               InputStream in = download(WebLibraryUrls.getStoryUrlCover(luid));
+               InputStream in = post(WebLibraryUrls.getStoryUrlCover(luid));
                try {
                        return new Image(in);
                } finally {
@@ -155,37 +159,48 @@ public class WebLibrary extends BasicLibrary {
        }
 
        @Override
-       public Image getCustomSourceCover(final String source) throws IOException {
-               // TODO maybe global system in BasicLib ?
-               return null;
+       public Image getCustomSourceCover(String source) throws IOException {
+               InputStream in = post(WebLibraryUrls.getCoverUrlSource(source));
+               try {
+                       return new Image(in);
+               } finally {
+                       in.close();
+               }
        }
 
        @Override
-       public Image getCustomAuthorCover(final String author) throws IOException {
-               // TODO maybe global system in BasicLib ?
-               return null;
+       public Image getCustomAuthorCover(String author) throws IOException {
+               InputStream in = post(WebLibraryUrls.getCoverUrlAuthor(author));
+               try {
+                       return new Image(in);
+               } finally {
+                       in.close();
+               }
        }
 
        @Override
        public void setSourceCover(String source, String luid) throws IOException {
-               // TODO Auto-generated method stub
-               throw new IOException("Not implemented yet");
+               Map<String, String> post = new HashMap<String, String>();
+               post.put("luid", luid);
+               post(WebLibraryUrls.getCoverUrlSource(source), post).close();
        }
 
        @Override
        public void setAuthorCover(String author, String luid) throws IOException {
-               // TODO Auto-generated method stub
-               throw new IOException("Not implemented yet");
+               Map<String, String> post = new HashMap<String, String>();
+               post.put("luid", luid);
+               post(WebLibraryUrls.getCoverUrlAuthor(author), post).close();
        }
 
        @Override
        public synchronized Story getStory(final String luid, Progress pg)
                        throws IOException {
-
-               // TODO: pg
+               if (pg == null) {
+                       pg = new Progress();
+               }
 
                Story story;
-               InputStream in = download(WebLibraryUrls.getStoryUrlJson(luid));
+               InputStream in = post(WebLibraryUrls.getStoryUrlJson(luid));
                try {
                        JSONObject json = new JSONObject(IOUtils.readSmallStream(in));
                        story = JsonIO.toStory(json);
@@ -193,13 +208,19 @@ public class WebLibrary extends BasicLibrary {
                        in.close();
                }
 
+               int max = 0;
+               for (Chapter chap : story) {
+                       max += chap.getParagraphs().size();
+               }
+               pg.setMinMax(0, max);
+
                story.getMeta().setCover(getCover(luid));
                int chapNum = 1;
                for (Chapter chap : story) {
                        int number = 1;
                        for (Paragraph para : chap) {
                                if (para.getType() == ParagraphType.IMAGE) {
-                                       InputStream subin = download(
+                                       InputStream subin = post(
                                                        WebLibraryUrls.getStoryUrl(luid, chapNum, number));
                                        try {
                                                para.setContentImage(new Image(subin));
@@ -208,19 +229,21 @@ public class WebLibrary extends BasicLibrary {
                                        }
                                }
 
+                               pg.add(1);
                                number++;
                        }
 
                        chapNum++;
                }
 
+               pg.done();
                return story;
        }
 
        @Override
        protected List<MetaData> getMetas(Progress pg) throws IOException {
                List<MetaData> metas = new ArrayList<MetaData>();
-               InputStream in = download(WebLibraryUrls.LIST_URL_METADATA);
+               InputStream in = post(WebLibraryUrls.LIST_URL_METADATA);
                JSONArray jsonArr = new JSONArray(IOUtils.readSmallStream(in));
                for (int i = 0; i < jsonArr.length(); i++) {
                        JSONObject json = jsonArr.getJSONObject(i);
@@ -233,8 +256,9 @@ public class WebLibrary extends BasicLibrary {
        @Override
        // Could work (more slowly) without it
        public MetaData imprt(final URL url, Progress pg) throws IOException {
-               if (true)
-                       throw new IOException("Not implemented yet");
+               if (pg == null) {
+                       pg = new Progress();
+               }
 
                // Import the file locally if it is actually a file
 
@@ -244,8 +268,44 @@ public class WebLibrary extends BasicLibrary {
 
                // Import it remotely if it is an URL
 
-               // TODO
-               return super.imprt(url, pg);
+               try {
+                       String luid = null;
+
+                       Map<String, String> post = new HashMap<String, String>();
+                       post.put("url", url.toString());
+                       InputStream in = post(WebLibraryUrls.IMPRT_URL_IMPORT, post);
+                       try {
+                               luid = IOUtils.readSmallStream(in);
+                       } finally {
+                               in.close();
+                       }
+
+                       Progress subPg = null;
+                       do {
+                               try {
+                                       Thread.sleep(2000);
+                               } catch (InterruptedException e) {
+                               }
+
+                               in = post(WebLibraryUrls.getImprtProgressUrl(luid));
+                               try {
+                                       subPg = JsonIO.toProgress(
+                                                       new JSONObject(IOUtils.readSmallStream(in)));
+                               } finally {
+                                       in.close();
+                               }
+                       } while (subPg != null);
+
+                       in = post(WebLibraryUrls.getStoryUrlMetadata(luid));
+                       try {
+                               return JsonIO.toMetaData(
+                                               new JSONObject(IOUtils.readSmallStream(in)));
+                       } finally {
+                               in.close();
+                       }
+               } finally {
+                       pg.done();
+               }
        }
 
        @Override
@@ -253,8 +313,24 @@ public class WebLibrary extends BasicLibrary {
        protected synchronized void changeSTA(final String luid,
                        final String newSource, final String newTitle,
                        final String newAuthor, Progress pg) throws IOException {
-               // TODO
-               super.changeSTA(luid, newSource, newTitle, newAuthor, pg);
+               MetaData meta = getInfo(luid);
+               if (meta != null) {
+                       if (!meta.getSource().equals(newSource)) {
+                               Map<String, String> post = new HashMap<String, String>();
+                               post.put("value", newSource);
+                               post(WebLibraryUrls.getStoryUrlSource(luid), post).close();
+                       }
+                       if (!meta.getTitle().equals(newTitle)) {
+                               Map<String, String> post = new HashMap<String, String>();
+                               post.put("value", newTitle);
+                               post(WebLibraryUrls.getStoryUrlTitle(luid), post).close();
+                       }
+                       if (!meta.getAuthor().equals(newAuthor)) {
+                               Map<String, String> post = new HashMap<String, String>();
+                               post.put("value", newAuthor);
+                               post(WebLibraryUrls.getStoryUrlAuthor(luid), post).close();
+                       }
+               }
        }
 
        @Override
@@ -270,7 +346,7 @@ public class WebLibrary extends BasicLibrary {
        // The following methods are only used by Save and Delete in BasicLibrary:
 
        @Override
-       protected int getNextId() {
+       protected String getNextId() {
                throw new java.lang.InternalError("Should not have been called");
        }
 
@@ -293,10 +369,18 @@ public class WebLibrary extends BasicLibrary {
        }
 
        // starts with "/", never NULL
-       private InputStream download(String path) throws IOException {
+       private InputStream post(String path) throws IOException {
+               return post(path, null);
+       }
+
+       // starts with "/", never NULL
+       private InputStream post(String path, Map<String, String> post)
+                       throws IOException {
                URL url = new URL(host + ":" + port + path);
 
-               Map<String, String> post = new HashMap<String, String>();
+               if (post == null) {
+                       post = new HashMap<String, String>();
+               }
                post.put("login", subkey);
                post.put("password", key);
 
index 97f2f0e8f69c6c07e217e1022ee4aa0fa96eaa4d..5cda3b5d712e6aa062ca87e9b16b4d157a40752f 100644 (file)
@@ -3,7 +3,9 @@ package be.nikiroo.fanfix.library;
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.net.URL;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
@@ -25,6 +27,7 @@ import be.nikiroo.utils.LoginResult;
 import be.nikiroo.utils.NanoHTTPD;
 import be.nikiroo.utils.NanoHTTPD.Response;
 import be.nikiroo.utils.NanoHTTPD.Response.Status;
+import be.nikiroo.utils.Progress;
 
 public class WebLibraryServer extends WebLibraryServerHtml {
        class WLoginResult extends LoginResult {
@@ -72,6 +75,8 @@ public class WebLibraryServer extends WebLibraryServerHtml {
        private List<String> whitelist;
        private List<String> blacklist;
 
+       private Map<String, Progress> imprts = new HashMap<String, Progress>();
+
        public WebLibraryServer(boolean secure) throws IOException {
                super(secure);
 
@@ -182,17 +187,17 @@ public class WebLibraryServer extends WebLibraryServerHtml {
        // /story/luid/json <-- json, whole chapter (no images)
        @Override
        protected Response getStoryPart(String uri, WLoginResult login) {
-               String[] cover = uri.split("/");
+               String[] uriParts = uri.split("/");
                int off = 2;
 
-               if (cover.length < off + 2) {
+               if (uriParts.length < off + 2) {
                        return NanoHTTPD.newFixedLengthResponse(Status.BAD_REQUEST,
                                        NanoHTTPD.MIME_PLAINTEXT, null);
                }
 
-               String luid = cover[off + 0];
-               String chapterStr = cover[off + 1];
-               String imageStr = cover.length < off + 3 ? null : cover[off + 2];
+               String luid = uriParts[off + 0];
+               String chapterStr = uriParts[off + 1];
+               String imageStr = uriParts.length < off + 3 ? null : uriParts[off + 2];
 
                // 1-based (0 = desc)
                int chapter = 0;
@@ -228,7 +233,7 @@ public class WebLibraryServer extends WebLibraryServerHtml {
                InputStream in = null;
                try {
                        if ("cover".equals(chapterStr)) {
-                               Image img = cover(luid, login);
+                               Image img = storyCover(luid, login);
                                if (img != null) {
                                        in = img.newInputStream();
                                }
@@ -287,6 +292,169 @@ public class WebLibraryServer extends WebLibraryServerHtml {
                return newInputStreamResponse(mimeType, in);
        }
 
+       // /story/luid/source
+       // /story/luid/title
+       // /story/luid/author
+       @Override
+       protected Response setStoryPart(String uri, String value,
+                       WLoginResult login) throws IOException {
+               String[] uriParts = uri.split("/");
+               int off = 2; // "" and "story"
+
+               if (uriParts.length < off + 2) {
+                       return NanoHTTPD.newFixedLengthResponse(Status.BAD_REQUEST,
+                                       NanoHTTPD.MIME_PLAINTEXT, "Invalid story part request");
+               }
+
+               String luid = uriParts[off + 0];
+               String type = uriParts[off + 1];
+
+               if (!Arrays.asList("source", "title", "author").contains(type)) {
+                       return NanoHTTPD.newFixedLengthResponse(Status.BAD_REQUEST,
+                                       NanoHTTPD.MIME_PLAINTEXT,
+                                       "Invalid SET story part: " + type);
+               }
+
+               if (meta(luid, login) != null) {
+                       BasicLibrary lib = Instance.getInstance().getLibrary();
+                       if ("source".equals(type)) {
+                               lib.changeSource(luid, value, null);
+                       } else if ("title".equals(type)) {
+                               lib.changeTitle(luid, value, null);
+                       } else if ("author".equals(type)) {
+                               lib.changeAuthor(luid, value, null);
+                       }
+               }
+
+               return newInputStreamResponse(NanoHTTPD.MIME_PLAINTEXT, null);
+       }
+
+       @Override
+       protected Response getCover(String uri, WLoginResult login)
+                       throws IOException {
+               String[] uriParts = uri.split("/");
+               int off = 2; // "" and "cover"
+
+               if (uriParts.length < off + 2) {
+                       return NanoHTTPD.newFixedLengthResponse(Status.BAD_REQUEST,
+                                       NanoHTTPD.MIME_PLAINTEXT, "Invalid cover request");
+               }
+
+               String type = uriParts[off + 0];
+               String id = uriParts[off + 1];
+
+               InputStream in = null;
+
+               if ("story".equals(type)) {
+                       Image img = storyCover(id, login);
+                       if (img != null) {
+                               in = img.newInputStream();
+                       }
+               } else if ("source".equals(type)) {
+                       Image img = sourceCover(id, login);
+                       if (img != null) {
+                               in = img.newInputStream();
+                       }
+               } else if ("author".equals(type)) {
+                       Image img = authorCover(id, login);
+                       if (img != null) {
+                               in = img.newInputStream();
+                       }
+               } else {
+                       return NanoHTTPD.newFixedLengthResponse(Status.BAD_REQUEST,
+                                       NanoHTTPD.MIME_PLAINTEXT,
+                                       "Invalid GET cover type: " + type);
+               }
+
+               // TODO: get correct image type
+               return newInputStreamResponse("image/png", in);
+       }
+
+       @Override
+       protected Response setCover(String uri, String luid, WLoginResult login)
+                       throws IOException {
+               String[] uriParts = uri.split("/");
+               int off = 2; // "" and "cover"
+
+               if (uriParts.length < off + 2) {
+                       return NanoHTTPD.newFixedLengthResponse(Status.BAD_REQUEST,
+                                       NanoHTTPD.MIME_PLAINTEXT, "Invalid cover request");
+               }
+
+               String type = uriParts[off + 0];
+               String id = uriParts[off + 1];
+
+               if ("source".equals(type)) {
+                       sourceCover(id, login, luid);
+               } else if ("author".equals(type)) {
+                       authorCover(id, login, luid);
+               } else {
+                       return NanoHTTPD.newFixedLengthResponse(Status.BAD_REQUEST,
+                                       NanoHTTPD.MIME_PLAINTEXT,
+                                       "Invalid SET cover type: " + type);
+               }
+
+               return newInputStreamResponse(NanoHTTPD.MIME_PLAINTEXT, null);
+       }
+
+       @Override
+       protected Response imprt(String uri, String urlStr, WLoginResult login)
+                       throws IOException {
+               final BasicLibrary lib = Instance.getInstance().getLibrary();
+
+               final URL url = new URL(urlStr);
+               final Progress pg = new Progress();
+               final String luid = lib.getNextId();
+
+               synchronized (imprts) {
+                       imprts.put(luid, pg);
+               }
+
+               new Thread(new Runnable() {
+                       @Override
+                       public void run() {
+                               try {
+                                       lib.imprt(url, pg);
+                               } catch (IOException e) {
+                                       Instance.getInstance().getTraceHandler().error(e);
+                               } finally {
+                                       synchronized (imprts) {
+                                               imprts.remove(luid);
+                                       }
+                               }
+                       }
+               }, "Import story: " + urlStr).start();
+
+               lib.imprt(url, pg);
+
+               return NanoHTTPD.newFixedLengthResponse(Status.OK,
+                               NanoHTTPD.MIME_PLAINTEXT, luid);
+       }
+
+       @Override
+       protected Response imprtProgress(String uri, WLoginResult login) {
+               String[] uriParts = uri.split("/");
+               int off = 2; // "" and "import"
+
+               if (uriParts.length < off + 1) {
+                       return NanoHTTPD.newFixedLengthResponse(Status.BAD_REQUEST,
+                                       NanoHTTPD.MIME_PLAINTEXT, "Invalid cover request");
+               }
+
+               String luid = uriParts[off + 0];
+
+               Progress pg = null;
+               synchronized (imprts) {
+                       pg = imprts.get(luid);
+               }
+               if (pg != null) {
+                       return NanoHTTPD.newFixedLengthResponse(Status.OK,
+                                       "application/json", JsonIO.toJson(pg).toString());
+               }
+
+               return newInputStreamResponse(NanoHTTPD.MIME_PLAINTEXT, null);
+       }
+
        @Override
        protected List<MetaData> metas(WLoginResult login) throws IOException {
                BasicLibrary lib = Instance.getInstance().getLibrary();
@@ -348,7 +516,8 @@ public class WebLibraryServer extends WebLibraryServerHtml {
                return meta;
        }
 
-       private Image cover(String luid, WLoginResult login) throws IOException {
+       private Image storyCover(String luid, WLoginResult login)
+                       throws IOException {
                MetaData meta = meta(luid, login);
                if (meta != null) {
                        BasicLibrary lib = Instance.getInstance().getLibrary();
@@ -358,13 +527,74 @@ public class WebLibraryServer extends WebLibraryServerHtml {
                return null;
        }
 
+       private Image authorCover(String author, WLoginResult login)
+                       throws IOException {
+               Image img = null;
+
+               List<MetaData> metas = new MetaResultList(metas(login)).filter(null,
+                               author, null);
+               if (metas.size() > 0) {
+                       BasicLibrary lib = Instance.getInstance().getLibrary();
+                       img = lib.getCustomAuthorCover(author);
+                       if (img == null)
+                               img = lib.getCover(metas.get(0).getLuid());
+               }
+
+               return img;
+
+       }
+
+       private void authorCover(String author, WLoginResult login, String luid)
+                       throws IOException {
+               if (meta(luid, login) != null) {
+                       List<MetaData> metas = new MetaResultList(metas(login)).filter(null,
+                                       author, null);
+                       if (metas.size() > 0) {
+                               BasicLibrary lib = Instance.getInstance().getLibrary();
+                               lib.setAuthorCover(author, luid);
+                       }
+               }
+       }
+
+       private Image sourceCover(String source, WLoginResult login)
+                       throws IOException {
+               Image img = null;
+
+               List<MetaData> metas = new MetaResultList(metas(login)).filter(source,
+                               null, null);
+               if (metas.size() > 0) {
+                       BasicLibrary lib = Instance.getInstance().getLibrary();
+                       img = lib.getCustomSourceCover(source);
+                       if (img == null)
+                               img = lib.getCover(metas.get(0).getLuid());
+               }
+
+               return img;
+       }
+
+       private void sourceCover(String source, WLoginResult login, String luid)
+                       throws IOException {
+               if (meta(luid, login) != null) {
+                       List<MetaData> metas = new MetaResultList(metas(login))
+                                       .filter(source, null, null);
+                       if (metas.size() > 0) {
+                               BasicLibrary lib = Instance.getInstance().getLibrary();
+                               lib.setSourceCover(source, luid);
+                       }
+               }
+       }
+
        private boolean isAllowed(MetaData meta, WLoginResult login) {
-               if (login.isWl() && !whitelist.isEmpty()
-                               && !whitelist.contains(meta.getSource())) {
-                       return false;
+               MetaResultList one = new MetaResultList(Arrays.asList(meta));
+               if (login.isWl() && !whitelist.isEmpty()) {
+                       if (one.filter(whitelist, null, null).isEmpty()) {
+                               return false;
+                       }
                }
-               if (login.isBl() && blacklist.contains(meta.getSource())) {
-                       return false;
+               if (login.isBl() && !blacklist.isEmpty()) {
+                       if (!one.filter(blacklist, null, null).isEmpty()) {
+                               return false;
+                       }
                }
 
                return true;
index c28188cde5467746b21e5f5f9905b9aeede978db..a534b4cdafbbdd8ec1c4c6b373bb7fc2953ec58c 100644 (file)
@@ -47,12 +47,26 @@ abstract class WebLibraryServerHtml implements Runnable {
 
        abstract protected Response getStoryPart(String uri, WLoginResult login);
 
+       abstract protected Response setStoryPart(String uri, String value,
+                       WLoginResult login) throws IOException;
+
+       abstract protected Response getCover(String uri, WLoginResult login)
+                       throws IOException;
+
+       abstract protected Response setCover(String uri, String luid,
+                       WLoginResult login) throws IOException;
+
        abstract protected List<MetaData> metas(WLoginResult login)
                        throws IOException;
 
        abstract protected Story story(String luid, WLoginResult login)
                        throws IOException;
 
+       protected abstract Response imprt(String uri, String url,
+                       WLoginResult login) throws IOException;
+
+       protected abstract Response imprtProgress(String uri, WLoginResult login);
+
        public WebLibraryServerHtml(boolean secure) throws IOException {
                Integer port = Instance.getInstance().getConfig()
                                .getInteger(Config.SERVER_PORT);
@@ -162,16 +176,35 @@ abstract class WebLibraryServerHtml implements Runnable {
                                                                rep = newFixedLengthResponse(Status.OK,
                                                                                MIME_PLAINTEXT,
                                                                                Version.getCurrentVersion().toString());
+                                                       } else if (WebLibraryUrls.isCoverUrl(uri)) {
+                                                               String luid = params.get("luid");
+                                                               if (luid != null) {
+                                                                       rep = setCover(uri, luid, login);
+                                                               } else {
+                                                                       rep = getCover(uri, login);
+                                                               }
                                                        } else if (WebLibraryUrls.isListUrl(uri)) {
                                                                rep = getList(uri, login);
                                                        } else if (WebLibraryUrls.isStoryUrl(uri)) {
-                                                               rep = getStoryPart(uri, login);
+                                                               String value = params.get("value");
+                                                               if (value != null) {
+                                                                       rep = setStoryPart(uri, value, login);
+                                                               } else {
+                                                                       rep = getStoryPart(uri, login);
+                                                               }
                                                        } else if (WebLibraryUrls.isViewUrl(uri)) {
                                                                rep = getViewer(cookies, uri, login);
                                                        } else if (WebLibraryUrls.LOGOUT_URL.equals(uri)) {
                                                                session.getCookies().delete("cookie");
                                                                cookies.remove("cookie");
                                                                rep = loginPage(login(false, false), uri);
+                                                       } else if (WebLibraryUrls.isImprtUrl(uri)) {
+                                                               String url = params.get("url");
+                                                               if (url != null) {
+                                                                       rep = imprt(uri, url, login);
+                                                               } else {
+                                                                       rep = imprtProgress(uri, login);
+                                                               }
                                                        } else {
                                                                getTraceHandler().error(
                                                                                "Supported URL was not processed: "
@@ -218,7 +251,9 @@ abstract class WebLibraryServerHtml implements Runnable {
                        }
                };
 
-               if (ssf != null) {
+               if (ssf != null)
+
+               {
                        getTraceHandler().trace("Install SSL on the web server...");
                        server.makeSecure(ssf, null);
                        getTraceHandler().trace("Done.");
index be4cf256bd154297e51a65ce3bdb78a52b96ef55..41f1c82feb17c2312ddc3868f5fd9176f3886c59 100644 (file)
@@ -17,11 +17,37 @@ class WebLibraryUrls {
        static private final String STORY_URL_COVER = STORY_URL_BASE
                        + "{luid}/cover";
        static private final String STORY_URL_JSON = STORY_URL_BASE + "{luid}/json";
+       static private final String STORY_URL_METADATA = STORY_URL_BASE
+                       + "{luid}/metadata";
+
+       // GET/SET ("value" param -> set STA to this value)
+       static private final String STORY_URL_SOURCE = STORY_URL_BASE
+                       + "{luid}/source";
+       static private final String STORY_URL_TITLE = STORY_URL_BASE
+                       + "{luid}/title";
+       static private final String STORY_URL_AUTHOR = STORY_URL_BASE
+                       + "{luid}/author";
 
        static private final String LIST_URL_BASE = "/list/";
 
        static public final String LIST_URL_METADATA = LIST_URL_BASE + "metadata";
 
+       // "import" requires param "url" and return an luid, "/{luid}" return
+       // progress status as a JSON Progress or 404 if none (done or failed)
+       static private final String IMPRT_URL_BASE = "/import/";
+       static private final String IMPRT_URL_PROGRESS = IMPRT_URL_BASE + "{luid}";
+       static public final String IMPRT_URL_IMPORT = IMPRT_URL_BASE + "import";
+
+       // GET/SET ("luid" param -> set cover to the cover of this story -- not ok
+       // for /cover/story/)
+       static private final String COVER_URL_BASE = "/cover/";
+       static private final String COVER_URL_STORY = COVER_URL_BASE
+                       + "story/{luid}";
+       static private final String COVER_URL_AUTHOR = COVER_URL_BASE
+                       + "author/{author}";
+       static private final String COVER_URL_SOURCE = COVER_URL_BASE
+                       + "source/{source}";
+
        static public String getViewUrl(String luid, Integer chap, Integer para) {
                return VIEWER_URL //
                                .replace("{luid}", luid) //
@@ -47,10 +73,50 @@ class WebLibraryUrls {
                                .replace("{luid}", luid);
        }
 
+       static public String getStoryUrlSource(String luid) {
+               return STORY_URL_SOURCE //
+                               .replace("{luid}", luid);
+       }
+
+       static public String getStoryUrlTitle(String luid) {
+               return STORY_URL_TITLE//
+                               .replace("{luid}", luid);
+       }
+
+       static public String getStoryUrlAuthor(String luid) {
+               return STORY_URL_AUTHOR //
+                               .replace("{luid}", luid);
+       }
+
+       static public String getStoryUrlMetadata(String luid) {
+               return STORY_URL_METADATA //
+                               .replace("{luid}", luid);
+       }
+
+       static public String getImprtProgressUrl(String luid) {
+               return IMPRT_URL_PROGRESS //
+                               .replace("{luid}", luid);
+       }
+
        static public boolean isSupportedUrl(String url) {
                return INDEX_URL.equals(url) || VERSION_URL.equals(url)
                                || LOGOUT_URL.equals(url) || isViewUrl(url) || isStoryUrl(url)
-                               || isListUrl(url);
+                               || isListUrl(url) || isCoverUrl(url) || isImprtUrl(url);
+       }
+
+       static public String getCoverUrlStory(String luid) {
+               return COVER_URL_STORY //
+                               .replace("{luid}", luid);
+       }
+
+       static public String getCoverUrlSource(String source) {
+               return COVER_URL_SOURCE //
+                               .replace("{source}", source);
+       }
+
+       static public String getCoverUrlAuthor(String author) {
+               return COVER_URL_AUTHOR //
+                               .replace("{author}", author);
        }
 
        static public boolean isViewUrl(String url) {
@@ -64,4 +130,12 @@ class WebLibraryUrls {
        static public boolean isListUrl(String url) {
                return url != null && url.startsWith(LIST_URL_BASE);
        }
+
+       static public boolean isCoverUrl(String url) {
+               return url != null && url.startsWith(COVER_URL_BASE);
+       }
+
+       static public boolean isImprtUrl(String url) {
+               return url != null && url.startsWith(IMPRT_URL_BASE);
+       }
 }