From 57d73018006aac60477fbf257d5e6a30cde378ad Mon Sep 17 00:00:00 2001
From: philc <phc@ndda.fr>
Date: Wed, 19 Mar 2025 17:06:01 +0100
Subject: [PATCH] modification articles for articles evaluation and comments
 ready for Peter

---
 apxtri/models/Articles.js |  15 +++
 apxtri/routes/articles.js |  86 +++++++++++++++
 schema/articles.json      | 224 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 325 insertions(+)
 create mode 100644 apxtri/models/Articles.js
 create mode 100644 apxtri/routes/articles.js
 create mode 100644 schema/articles.json

diff --git a/apxtri/models/Articles.js b/apxtri/models/Articles.js
new file mode 100644
index 0000000..e1b7f15
--- /dev/null
+++ b/apxtri/models/Articles.js
@@ -0,0 +1,15 @@
+const fs = require(`fs-extra`);
+const mustache = require(`mustache`);
+const path = require(`path`);
+const dayjs = require(`dayjs`);
+const Notifications = require(`./Notifications.js`);
+const Odmdb = require(`./Odmdb.js`);
+const Checkjson = require(`./Checkjson`);
+const conf = require(`../../objects/tribes/itm/adminapi.json`);
+const currentmod = "Articles";
+const log = conf.api.activelog.includes(currentmod);
+
+
+const Articles={}
+
+module.exports=Articles;
\ No newline at end of file
diff --git a/apxtri/routes/articles.js b/apxtri/routes/articles.js
new file mode 100644
index 0000000..2f71cef
--- /dev/null
+++ b/apxtri/routes/articles.js
@@ -0,0 +1,86 @@
+const fs = require(`fs-extra`);
+const path = require(`path`);
+const express = require(`express`);
+// Middlewares
+const checkHeaders = require(`../middlewares/checkHeaders`);
+const isAuthenticated = require(`../middlewares/isAuthenticated`);
+// Classes
+const Articles = require(`../models/Articles`);
+
+const conf = require(`../../../adminapi/objects/tribes/itm/adminapi.json`);
+const currentmod = "Articles";
+const log = conftrib.activelog.includes(currentmod);
+
+const router = express.Router();
+
+/**
+ * @api {GET} /adminapi/articles/evaluation/:tribe/:articleid/:evaluation -set article evaluation
+ * @apiName articleevaluation
+ * @apiGroup Articles
+ * @apiDescription Get evaluation about an articleid
+ *
+ * @apiParam {string} tribe an existing tribe where articles exist
+ * @apiParam {string} articleid an existing articleid in tribe/objects/articles/itm
+ * @apiParam {string} evaluation a value from 0 to 4 or follow
+ *
+ * @apiSuccess {object}  successfull
+ * @apiSuccessExample {json} successfullmessage
+ * HTTP/1.1 200 OK
+ * {"status":200, "ref":"Articles", "msg":"evaluationsaved", "data":{article}}
+ *
+ * @apiError {object}  notfound
+ * @apiErrorexampleExample {json} notfound
+ * HTTP/1.1 200 OK
+ * {"status":404, "ref":"Articles", "msg":"notfound", "data":{articleid}}
+ *
+ */
+router.get(
+  "/evaluation/:tribe/:articleid/:evaluation",
+  checkHeaders,
+  async (req, res) => {
+    // @todo
+    // Check if tribe/objects/articles/articleid exist
+    // if evaluation between 0 and 4 then update article propertie "articleevaluations" by adding alias:evaluation if alias !=anonymous, if anonymous then add uuid:evaluation
+    // recalculate articlevalue with an average of all evaluation
+    // if evaluatiopn == follow then add alias to article.followupdate
+    res.status(200).json({
+      status: 200,
+      ref: "Articles",
+      msg: "evaluationsaved",
+      data: { article: req.params.articleid },
+    });
+  }
+);
+
+/**
+ * @api {post} adminapi/articles/comments  - pagan Post
+ * @apiName addcomments
+ * @apiGroup Articles
+ * @apiDescription
+ *  Add a comments to an articles or to another comments
+ * @apiBody {string} [articleid] concern by the comment
+ * @apiBody {string} [tribe] where the articleid is store
+ * @apiBody {string} [comment] the comment text
+ * @apiBody {string} [commentanswer] the position in a comment list in case of answer to a previous comment
+ * 
+ * @apiError {json} articleNotfound the tribe/objects/articles/itm does not exist 
+ * @apiErrorExample {json}
+ * HTTP/1.1 404 Not Found
+   {"status":404,"ref":"Articles","msg":"articleidnotfound","data":{}}
+ *
+ * @apiSuccess {object}  
+ * @apiSuccessExample {json} Success-Response:
+ * HTTP/1.1 200 OK
+ * {"status":200, "ref":"Articles", "msg":"commentsaved", "data":{}}
+ * 
+ */
+router.post("/comments", checkHeaders, isAuthenticated, async (req, res) => {
+  console.log('articles comment todo')
+  res.status(200).json({
+    status: 200,
+    ref: "Articles",
+    msg: "commentsaved",
+    data: {},
+  });
+});
+module.exports = router;
diff --git a/schema/articles.json b/schema/articles.json
new file mode 100644
index 0000000..0c98a58
--- /dev/null
+++ b/schema/articles.json
@@ -0,0 +1,224 @@
+{
+  "$schema": "https://json-schema.org/draft/2020-12/schema",
+  "$id": "/schema/articles",
+  "title": "Article",
+  "description": "Way to store data about articles",
+  "type": "object",
+  "properties": {
+    "articleid": {
+      "title": "Unique identification",
+      "description": "A unique uuid string identifying an article",
+      "type": "string",
+      "format": "uuid"
+    },
+    "title": {
+      "title": " Article title for SEO",
+      "description": "Use to create a url if needed",
+      "type": "string"
+    },
+    "description": {
+      "title": "Description for SEO",
+      "type": "string"
+    },
+    "imgseo": {
+      "title": "Image for SEO",
+      "type": "string",
+      "format": "url"
+    },
+    "url": {
+      "type": "string",
+      "format": "url",
+      "comment": "A web access of this article public or private"
+    },
+    "author": {
+      "title": "Auteur",
+      "type": "string",
+      "comment": "Can be different than owner"
+    },
+    "email": {
+      "title": "To contact author",
+      "format": "email",
+      "comment": "Hide to public but to be aware of a comment "
+    },
+    "owner": {
+      "title": "Owner of this article",
+      "description": "For accessright purpose this is always equal as alias",
+      "type": "string"
+    },
+    "dt_create": {
+      "title": "Creation date",
+      "type": "string",
+      "format": "date-time"
+    },
+    "dt_update": {
+      "type": "string",
+      "format": "date-time"
+    },
+    "dt_publish": {
+      "type": "string",
+      "format": "date-time"
+    },
+    "manualkeywords": {
+      "type": "array",
+      "items": {
+        "type": "string",
+        "enum": [
+          "tips",
+          "news",
+          "tutorial"
+        ]
+      }
+    },
+    "autokeywords": {
+      "type": "array",
+      "items": {
+        "type": "string"
+      }
+    },
+    "articleevaluations": {
+      "title": "key is an alias or uuid and value is an evaluation from 0 to 4",
+      "type": "object",
+      "patternProperties": {
+        "*": {
+          "title": "evaluation 0 dislike 4 like",
+          "type": "integer",
+          "minimum": 0,
+          "maximum": 4
+        }
+      },
+      "articlevalue": {
+        "type": "float",
+        "minimum": 0,
+        "maximum": 4
+      },
+      "followupdate": {
+        "type": "array",
+        "items": {
+          "title": "alias",
+          "type": "string"
+        }
+      },
+      "comments": {
+        "type": "array",
+        "items": {
+          "type": "object",
+          "properties": {
+            "comments": {
+              "type": "string",
+              "maxLength": 250
+            },
+            "dt_create": {
+              "title": "Creation date",
+              "type": "string",
+              "format": "date-time"
+            },
+            "alias": {
+              "type": "string"
+            },
+            "commenthash": {
+              "type": "string"
+            },
+            "answerto": {
+              "type": "integer",
+              "title": "position of the comments of this response comment"
+            }
+          }
+        }
+      },
+      "publiccontent": {
+        "type": "string"
+      },
+      "privatecontent": {
+        "type": "string"
+      }
+    },
+    "required": [
+      "articleid",
+      "owner",
+      "title",
+      "description"
+    ],
+    "additionalProperties": true,
+    "apxref": [],
+    "apxid": "articleid",
+    "apxuniquekey": [
+      "articleid"
+    ],
+    "apxidx": [
+      {
+        "name": "lst_articleid",
+        "type": "array",
+        "keyval": "articleid"
+      },
+      {
+        "name": "lst_author",
+        "type": "array",
+        "keyval": "author"
+      },
+      {
+        "name": "articleid",
+        "type": "view",
+        "keyval": "articleid",
+        "objkey": [
+          "articleid",
+          "title",
+          "description",
+          "imgseo",
+          "url",
+          "author",
+          "dt_create",
+          "dt_update",
+          "dt_publish",
+          "manualkeywords",
+          "autokeywords"
+        ],
+        "filter": ""
+      },
+      {
+        "name": "author_articleid",
+        "type": "distribution",
+        "keyval": "author",
+        "filter": ""
+      },
+      {
+        "name": "manualkeywords_articleid",
+        "type": "distribution",
+        "keyval": "manualkeywords",
+        "filter": ""
+      }
+    ],
+    "apxaccessrights": {
+      "owner": {
+        "C": [],
+        "D": [],
+        "R": [],
+        "U": [
+          "title",
+          "description",
+          "imgseo",
+          "url",
+          "author",
+          "dt_publish",
+          "manualkeywords",
+          "publiccontent",
+          "privatecontent"
+        ]
+      },
+      "persons": {
+        "R": [
+          "articleid",
+          "title",
+          "description",
+          "imgseo",
+          "url",
+          "author",
+          "dt_publish",
+          "manualkeywords",
+          "publiccontent",
+          "comments",
+          "articlevalue"
+        ]
+      }
+    }
+  }
+}
\ No newline at end of file