Ver Fonte

Refs #24 List user rights

isundil há 1 ano atrás
pai
commit
02cd5540d3

+ 19 - 0
router/api.js

@@ -58,6 +58,25 @@ module.exports = { register: app => {
         const result = Security.setAdmin(req, !!(access?.length || 0));
         app.routerUtils.jsonResponse(res, result);
     });
+    app.router.get("/api/accessAdmin/list", async (req, res) => {
+        app.routerUtils.onApiRequest(req, res);
+        if (!req.sessionObj?.accessList?.isAdmin)
+            return app.routerUtils.onBadRequest(res);
+        const access = await app.databaseHelper.fetch(AccessModel);
+        app.routerUtils.jsonResponse(res, access.map(i => {
+            const typeStr = [ "unknown", "ldapAccount", "email", "link", "every one" ][i.type];
+            const accessToStr = [ "unknown", "item", "tag", "meta", "everything", "admin"][i.accessTo];
+            const grantStr = [ "none", "read", "write", "read without meta"][i.grant];
+            return {
+                id: i.id,
+                type: typeStr,
+                typeData: i.typeData,
+                accessTo: accessToStr,
+                accessToData: i.accessToData,
+                grant: grantStr
+            };
+        }));
+    });
     app.router.post("/api/media/:id/tag/del/:tag", async (req, res) => {
         app.routerUtils.onApiRequest(req, res);
         if (!req.params.id ||!req.params.tag)

+ 30 - 1
static/public/css/style.css

@@ -267,7 +267,7 @@ body.filter-active #pch-navbar .bt-filter-inactive {
     margin-left: calc(var(--bs-badge-padding-x) / 2);
 }
 
-.login-wrapper {
+.login-wrapper,.share-wrapper {
     position: fixed;
     justify-content: center;
     align-items: center;
@@ -307,6 +307,35 @@ body.login-visible .login-wrapper {
     margin-right: auto;
 }
 
+.share-wrapper.hidden {
+    display: none;
+}
+.share-wrapper {
+    display: flex;
+    text-align: left;
+}
+#pch-share .modal-title {
+    flex: 1;
+}
+.share-wrapper .modal {
+    display: inline-flex;
+    flex-direction: column;
+    justify-content: center;
+    align-items: center;
+    position: static;
+    display: inline;
+    margin: 0;
+    width: auto;
+    height: auto;
+}
+#pch-share-container ul {
+    list-style-type: none;
+    padding: 0;
+}
+#pch-share {
+    min-width: max(100%, 425px);
+}
+
 .slider-value {
     display: inline;
     width: auto;

+ 2 - 3
static/public/js/uiAccess.js

@@ -52,15 +52,14 @@ async function logout(accessId, linkId) {
 }
 
 window.ReloadAccessList = function(accessList) {
-    document.getElementById("pch-navbar-reload");
-    document.getElementById("pch-navbar-share");
-
     if (accessList.isAdmin) {
         document.getElementById("pch-navbar-reload").classList.remove("hidden");
         document.getElementById("pch-navbar-share").classList.remove("hidden");
+        document.getElementById("pch-navbar-autotags").classList.remove("hidden");
     } else {
         document.getElementById("pch-navbar-reload").classList.add("hidden");
         document.getElementById("pch-navbar-share").classList.add("hidden");
+        document.getElementById("pch-navbar-autotags").classList.add("hidden");
     }
 
     let getIconForType = type => {

+ 4 - 0
static/public/js/uiAutotags.js

@@ -0,0 +1,4 @@
+
+function showAutoTagsUi() {
+}
+

+ 1 - 0
static/public/js/uiCommon.js

@@ -20,6 +20,7 @@ $(() => {
 
     document.getElementById("pch-navbar-reload").addEventListener("click", () => reloadServerDb());
     document.getElementById("pch-navbar-share").addEventListener("click", () => showShareUi());
+    document.getElementById("pch-navbar-autotags").addEventListener("click", () => showAutoTagsUi());
     document.getElementById("fullScreenOverlay").addEventListener("click", triggerClosePopinsRequestHandlers);
     document.onClosePopinRequested = (hndl) => closePopinsRequestedHandlers.push(hndl);
 });

+ 136 - 1
static/public/js/uiShare.js

@@ -1,4 +1,139 @@
 
-function showShareUi() {
+$(() => {
+
+var windowDisplayed = false;
+var data = null;
+
+class ShareData {
+    dbId = 0;
+    typeId = "";
+    typeData = "";
+    accessToId = 0;
+    accessToData = "";
+    grant = 0;
+
+    constructor(data) {
+        this.dbId = data.id;
+        this.typeId = [ "unknown", "ldapAccount", "email", "link", "every one" ].indexOf(data.type);
+        this.typeData = data.typeData;
+        this.accessToId = [ "unknown", "item", "tag", "meta", "everything", "admin"].indexOf(data.accessTo);
+        this.accessToData = data.accessToData;
+        this.grant = [ "none", "read", "write", "read without meta"].indexOf(data.grant);
+    }
+
+    compare(b) {
+        if (this.typeId != b.typeId) return b.typeId - this.typeId;
+        if (this.accessToId != b.accessToId) return b.accessToId - this.accessToId;
+        if (this.grant != b.grant) return b.grant - this.grant;
+        return 0;
+    }
+}
+
+function getData() {
+    return new Promise((ok) => {
+        if (data)
+            return ok(data);
+        $.get("/api/accessAdmin/list", {}, okData => {
+            data = okData;
+            ok(okData);
+        });
+    });
+}
+
+async function buildShareItem(data) {
+    const htmlId = `collapseShareItem${data.dbId}`;
+    let container = document.createElement("li");
+    container.className = "accordion-item";
+    let header = document.createElement("h2");
+    header.className = "accordion-header";
+    let headerButton = document.createElement("button");
+    headerButton.className = "accordion-button bi " + (["bi-question-lg", "bi-database", "bi-envelope-at", "bi-link-45deg", "bi-people"][data.typeId]);
+    headerButton.type = "button";
+    headerButton.dataset.bsToggle = "collapse";
+    headerButton.dataset.bsTarget = `#${htmlId}`;
+    headerButton.textContent = data.typeData;
+    headerButton.ariaExpanded = false;
+    headerButton.ariaControls = htmlId;
+    let accordionBodyContainer = document.createElement("div");
+    accordionBodyContainer.className = "accordion-collapse collapse";
+    accordionBodyContainer.dataset.bsParent = "#pch-share-container";
+    accordionBodyContainer.id = htmlId;
+    let accordionBody = document.createElement("div");
+    accordionBody.className = "accordion-body";
+    let typeDivRow = document.createElement("div");
+    typeDivRow.className = "row";
+    let typeDiv = document.createElement("div");
+    typeDiv.className = "bi";
+    typeDiv.classList.add(["bi-question-lg", "bi-diagram-2", "bi-tags", "bi-braces-asterisk", "bi-people", "bi-gear"][data.accessToId]);
+    typeDiv.textContent = ["Unknown", "Single photo", "Tags", "Meta", "Everything", "Admin access"][data.accessToId];
+    if (data.accessToId === 1)
+        typeDiv.textContent += " (" +((await MediaStorage.Instance.getMedia(data.accessToData))?.fileName || "File not found") + ")";
+    else if (data.accessToId === 2)
+        typeDiv.textContent += ` (${data.accessToData})`;
+    else if (data.accessToId === 3)
+        typeDiv.textContent += ` (${data.accessToData})`;
+    if (data.accessToId !== 5) {
+        let grantDiv = document.createElement("div");
+        grantDiv.textContent = ["None", "Read Access", "Write Access", "Read Access (Strip meta)"][data.grant];
+        typeDiv.appendChild(grantDiv);
+    }
+
+    let deleteButtonRow = document.createElement("div");
+    let deleteButtonDiv = document.createElement("div");
+    let deleteButton = document.createElement("button");
+    deleteButtonRow.className = "row";
+    deleteButtonDiv.className = "col align-self-end";
+    deleteButton.className = "btn btn-danger";
+    deleteButton.textContent = "Revoke";
+    deleteButtonRow.appendChild(deleteButtonDiv);
+    deleteButtonDiv.appendChild(deleteButton);
+    deleteButton.addEventListener("click", () => {
+        console.log("Request to revoke " +data.dbId); // FIXME
+    });
+
+    header.appendChild(headerButton);
+    container.appendChild(header);
+    accordionBody.appendChild(typeDivRow);
+    typeDivRow.appendChild(typeDiv);
+    accordionBody.appendChild(deleteButtonRow);
+    accordionBodyContainer.appendChild(accordionBody);
+    container.appendChild(accordionBodyContainer);
+    return container;
+}
+
+async function buildShareItems(data) {
+    let container = document.createElement("ul");
+    for (let i of data)
+        container.appendChild(await buildShareItem(i));
+    return container;
+}
+
+window.showShareUi = async () => {
+    if (windowDisplayed)
+        return;
+    document.getElementById("pch-share-wrapper").classList.remove("hidden");
+    document.Title.pushTitle("Share");
+    document.body.classList.add("overlay-visible");
+    const data = ((await getData()) || []).map(x => new ShareData(x)).sort((a, b) => a.compare(b));
+    document.getElementById('pch-share-loading').classList.add("hidden");
+    const container = document.getElementById('pch-share-container');
+    container.innerHTML = "";
+    container.appendChild(await buildShareItems(data));
+    windowDisplayed = true;
 }
 
+window.closeShareUi = () => {
+    if (!windowDisplayed)
+        return;
+    document.getElementById("pch-share-wrapper").classList.add("hidden");
+    document.body.classList.remove("overlay-visible");
+    windowDisplayed = false;
+    document.Title.pop();
+}
+
+document.onClosePopinRequested(() => { window.closeShareUi(); });
+document.getElementById("pch-share-closeBt").addEventListener("click", window.closeShareUi);
+
+setTimeout(() => LoadingTasks.push(window.showShareUi), 1500);
+});
+

+ 1 - 0
templates/_footer.js

@@ -17,6 +17,7 @@ module.exports = `
 <script src="/public/js/uiAccess.js"></script>
 <script src="/public/js/uiFilter.js"></script>
 <script src="/public/js/uiShare.js"></script>
+<script src="/public/js/uiAutotags.js"></script>
 <script src="/public/js/chronology.js"></script>
 <script src="/public/js/common.js"></script>
 </body></html>`;

+ 1 - 1
templates/_fullPageMedia.js

@@ -18,5 +18,5 @@ module.exports = `
                 <div class="col col-12 col-xl-3"><div id="pch-fullPageDetail" class="container-fluid"></div></div>
             </div>
         </div>
-    </div>
+    </div></div></div>
     `;

+ 3 - 0
templates/_menu.js

@@ -11,6 +11,9 @@ module.exports = `
                 <li class="nav-item">
                     <a class="nav-link hidden" href="#" role="button" id="pch-navbar-share"><i class="bi bi-share">&nbsp;</i></a>
                 </li>
+                <li class="nav-item">
+                    <a class="nav-link hidden" href="#" role="button" id="pch-navbar-autotags"><i class="bi bi-tags">&nbsp;</i></a>
+                </li>
                 <li class="nav-item">
                     <a class="nav-link" id="pch-navbar-filterToggle" href="#" role="button">
                         <i class="bi bi-funnel bt-filter-inactive">&nbsp;</i>

+ 23 - 0
templates/_uiShare.js

@@ -0,0 +1,23 @@
+module.exports = `
+<div class="share-wrapper hidden" id="pch-share-wrapper">
+    <div id="pch-share" class="modal" role="dialog"><div class="modal-dialog"><div class="modal-content">
+        <div class="modal-header">
+            <h5 class="modal-title">Share</h5>
+            <button id="pch-share-closeBt" type="button" class="close" data-dismiss="modal" aria-label="Close">
+                <span aria-hidden="true">&times;</span>
+            </button>
+        </div>
+        <div class="container modal-body">
+            <div class="row">
+                <div class="container-fluid">
+                    <div id="pch-share-loading" class="spinner"><span class="spinner-grow">&nbsp;</span></div>
+                    <div id="pch-share-container" class="accordion"></div>
+                </div>
+            </div>
+        </div>
+        <div class="modal-footer">
+            <button type="button" class="btn btn-success">Add</button>
+        </div>
+    </div>
+</div>
+    `;

+ 1 - 2
templates/index.js

@@ -8,8 +8,7 @@ module.exports = require('./_header.js') +require('./_menu.js')
         <div class="spinner-grow"></div>
     </div>`
     +require('./_fullPageMedia.js')
-    +`
-</div>`
+    +require('./_uiShare.js')
     +`</div></div>`
     +require('./_login.js')
     +require('./_footer.js');