소스 검색

Display entity informations

isundil 4 년 전
부모
커밋
1f72fcaa29
12개의 변경된 파일139개의 추가작업 그리고 42개의 파일을 삭제
  1. 3 0
      LDAPManager.njsproj
  2. 6 0
      app.ts
  3. 52 0
      public/javascripts/entity.js
  4. 10 3
      public/stylesheets/main.css
  5. 3 2
      routes/category.ts
  6. 30 11
      routes/entity.ts
  7. 6 7
      routes/index.ts
  8. 2 5
      routes/login.ts
  9. 9 1
      src/LDAPSchema.ts
  10. 3 7
      src/Security.ts
  11. 2 2
      src/ldapInterface.ts
  12. 13 4
      views/entity.pug

+ 3 - 0
LDAPManager.njsproj

@@ -33,6 +33,9 @@
     <Content Include="public\javascripts\category.js">
       <SubType>Code</SubType>
     </Content>
+    <Content Include="public\javascripts\entity.js">
+      <SubType>Code</SubType>
+    </Content>
     <Content Include="public\javascripts\tree.js">
       <SubType>Code</SubType>
     </Content>

+ 6 - 0
app.ts

@@ -6,6 +6,8 @@ import route_index from './routes/index';
 import route_entity from './routes/entity';
 import { route_login, route_logout } from './routes/login';
 import LDAPFactory from './src/ldapInterface';
+import { Session } from './src/Security';
+import Security from './src/Security';
 
 const debug = require('debug')('my express app');
 const app = express();
@@ -14,6 +16,8 @@ declare global {
     namespace Express {
         interface Request {
             ldapManager: LDAPFactory
+            session: Session | null
+            isUserLogged: boolean
         }
     }
 }
@@ -28,6 +32,8 @@ app.use(bodyParser.urlencoded({ extended: true }));
 
 app.use((req, res, next) => {
     req.ldapManager = new LDAPFactory();
+    req.session = Security.GetSession(req);
+    req.isUserLogged = Security.IsUserLogged(req);
     res.socket && res.socket.once('close', () => {
         req.ldapManager.Release();
     });

+ 52 - 0
public/javascripts/entity.js

@@ -0,0 +1,52 @@
+((dn, inputs, ldifOutput) => {
+	let changes = [],
+		multipleValues = {};
+
+	function ComputeChanges() {
+		let actualChanges = [];
+		for (let i = 0; i < changes.length; ++i) {
+			let ch = changes[i];
+			if (!ch)
+				continue;
+			if (ch.initialValue.length && ch.newValue.length && (multipleValues[ch.attrName] || 0) === 1) {
+				actualChanges.push(`replace: ${ch.attrName}\n${ch.attrName}: ${ch.newValue}`);
+			} else {
+				if (ch.initialValue.length) {
+					if ((multipleValues[ch.attrName] || 0) === 1)
+						actualChanges.push(`delete: ${ch.attrName}`);
+					else
+						actualChanges.push(`delete: ${ch.attrName}\nattribute: ${ch.initialValue}`);
+				}
+				if (ch.newValue.length)
+					actualChanges.push(`add: ${ch.attrName}\n${ch.attrName}: ${ch.newValue}`);
+			}
+		}
+		if (!actualChanges.length)
+			return "";
+		actualChanges.sort((a, b) => b.localeCompare(a));
+		return `dn: ${dn}\nchangetype: modify\n` + actualChanges.join("\n-\n");
+	}
+	function UpdateLdif() {
+		ldifOutput.textContent = ComputeChanges();
+		ldifOutput.style.height = ldifOutput.scrollHeight + "px"
+	}
+
+	function onValueChanged(input) {
+		let initialValue = input.dataset.initialValue || "",
+			inputId = input.dataset.inputId,
+			newValue = input.value || "",
+			attrName = input.dataset.attributeName;
+		if (initialValue === newValue)
+			changes[inputId] = undefined;
+		else
+			changes[inputId] = { initialValue: initialValue, newValue: newValue, attrName: attrName };
+		UpdateLdif();
+	}
+
+	inputs.forEach(i => {
+		let attrName = i.dataset.attributeName;
+		if ((i.dataset.initialValue || "").length)
+			multipleValues[attrName] = (multipleValues[attrName] || 0) + 1;
+		i.addEventListener("change", e => onValueChanged(e.currentTarget))
+	});
+})(window['dn'], document.querySelectorAll(".LDAPAttribute > input"), document.getElementById("ldifOutput"));

+ 10 - 3
public/stylesheets/main.css

@@ -42,8 +42,8 @@ iframe#page {
 div.page {
     margin: 0 1em;
 }
-fieldset.LDAPClass {
-    margin-bottom: 1em;
+fieldset.changes {
+    margin: 1.5em 0;
 }
 fieldset.LDAPClass > legend {
     padding: 0 1em;
@@ -52,11 +52,18 @@ label.LDAPAttribute {
     display: block;
     margin: 3px;
 }
-label.LDAPAttribute>span {
+label.LDAPAttribute > span {
     display: inline-block;
     width: 250px;
 }
+label.LDAPAttribute > span.mandatory:after {
+    content: " (*)"
+}
 label.LDAPAttribute > input {
     display: inline-block;
     width: 450px;
+}
+#ldifOutput {
+    width: 100%;
+    height: auto;
 }

+ 3 - 2
routes/category.ts

@@ -6,6 +6,7 @@ const router = express.Router();
 import Security from '../src/Security';
 import { ILDAPManager } from '../src/ldapInterface';
 import LDAPEntry from '../src/LDAPEntry';
+import RouterUtils from '../src/RouterUtils';
 import ConfigManager, { LDAPAttribute, LDAPCategory } from '../src/ConfigLoader';
 
 function GetCurrentCategory(req: express.Request, defaultResult: LDAPCategory): LDAPCategory|null {
@@ -28,8 +29,8 @@ function DnToLink(dn: string): string {
 }
 
 router.get('/', (req: express.Request, res: express.Response) => {
-    if (!Security.requireLoggedUser(req, res))
-        return;
+    if (!req.isUserLogged)
+        return RouterUtils.Redirect(res, "/login");
     req.ldapManager.GetInstance().then((ldap: ILDAPManager): void => {
         ldap.GetTree().then(root => {
             let categories = ConfigManager.GetInstance().GetCategories();

+ 30 - 11
routes/entity.ts

@@ -4,8 +4,9 @@
 import express = require('express');
 const router = express.Router();
 import Security from '../src/Security';
+import RouterUtils from '../src/RouterUtils';
 import { ILDAPManager } from '../src/ldapInterface';
-import { LDAPSchemaObjectClass } from '../src/LDAPSchema';
+import { LDAPSchemaObjectClass, ClassType } from '../src/LDAPSchema';
 
 function LDAPEntryToAttributes(entry: Map<string, Array<string>>): any {
     let result: any = [];
@@ -16,16 +17,14 @@ function LDAPEntryToAttributes(entry: Map<string, Array<string>>): any {
 
 class AttributesByClasses {
     public constructor(entry: Map<string, string[]>, classes: Map<string, LDAPSchemaObjectClass>) {
-        let oClasses: LDAPSchemaObjectClass[] = new Array();
-
         for (let eClass of entry.get("objectClass") || []) {
             this.fEntries.set(eClass, new Map());
             let cl = classes.get(eClass);
-            cl && oClasses.push(cl);
+            cl && this.fObjectClasses.push(cl);
 		}
         for (let [i, j] of entry) {
             let found = false;
-            for (let oc of oClasses) {
+            for (let oc of this.fObjectClasses) {
                 if (oc.HasAttribute(i)) {
                     this.fEntries.get(oc.GetName())?.set(i, j);
                     found = true;
@@ -35,7 +34,7 @@ class AttributesByClasses {
             if (!found)
                 this.fUnmapped.set(i, j);
         }
-        for (let klass of oClasses) {
+        for (let klass of this.fObjectClasses) {
             let className = klass.GetName();
             let classContent = this.fEntries.get(className);
 
@@ -44,11 +43,18 @@ class AttributesByClasses {
                 this.fEntries.set(className, classContent);
             }
             for (let attr of klass.ListAttributes())
-                !classContent.has(attr) && classContent.set(attr, new Array());
+                !classContent.has(attr) && !entry.has(attr) && classContent.set(attr, new Array());
             this.fEntries.set(className, classContent);
 		}
     }
 
+    public IsMandatoryAttr(attr: string): boolean {
+        for (let klass of this.fObjectClasses)
+            if (klass.HasMust(attr))
+                return true;
+        return false;
+	}
+
     public ToMap(): any {
         let result: any = {};
         for (let [ocKey, vals] of this.fEntries) {
@@ -69,17 +75,18 @@ class AttributesByClasses {
         return result;
 	}
 
+    private fObjectClasses: LDAPSchemaObjectClass[] = new Array();
     private fEntries: Map<string, Map<string, string[]>> = new Map();
     private fUnmapped: Map<string, string[]> = new Map();
 }
 
 router.get('/:dn', (req: express.Request, res: express.Response) => {
-    if (!Security.requireLoggedUser(req, res))
-        return;
+    if (!req.isUserLogged)
+        return RouterUtils.Redirect(res, "/login");
     let ldapManager: ILDAPManager;
     let entry: Map<string, string[]>;
     req.ldapManager.GetInstance()
-        .then(_ldapManager => { ldapManager = _ldapManager; return ldapManager.GetEntry(req.params.dn) })
+        .then(_ldapManager => { ldapManager = _ldapManager; return ldapManager.GetEntry(req.params.dn); })
         .then(_entry => { entry = _entry; return ldapManager.GetSchema() }).then(schema => {
             let classes: AttributesByClasses = new AttributesByClasses(entry, schema);
             let dn = (entry.get("dn") || [])[0];
@@ -87,7 +94,19 @@ router.get('/:dn', (req: express.Request, res: express.Response) => {
             res.render('entity', {
                 dn: dn || req.params.dn,
                 attributes: classes.ToMap(),
-                classes: classes.GetObjectClasses()
+                classes: classes.GetObjectClasses(),
+                getType: (klass: string): string => {
+                    switch (schema.get(klass)?.GetType()) {
+                        case ClassType.eAbstract:
+                            return "abstract";
+                        case ClassType.eAuxiliary:
+                            return "auxiliary";
+                        case ClassType.eStructural:
+                            return "structural";
+                    }
+                    return "Unknown";
+                },
+                isMandatory: (attr: string): boolean => classes.IsMandatoryAttr(attr)
             });
     });
 });

+ 6 - 7
routes/index.ts

@@ -3,9 +3,7 @@
  */
 import express = require('express');
 const router = express.Router();
-import Security from '../src/Security';
-import { ILDAPManager } from '../src/ldapInterface';
-import LDAPEntry from '../src/LDAPEntry';
+import RouterUtils from '../src/RouterUtils';
 import ConfigManager, { LDAPAttribute, LDAPCategory } from '../src/ConfigLoader';
 
 function GetCurrentCategory(req: express.Request, defaultResult: LDAPCategory): LDAPCategory|null {
@@ -28,8 +26,8 @@ function DnToLink(dn: string): string {
 }
 
 router.get('/', (req: express.Request, res: express.Response) => {
-    if (!Security.requireLoggedUser(req, res))
-        return;
+    if (!req.isUserLogged)
+        return RouterUtils.Redirect(res, "/login");
     req.ldapManager.GetInstance().then(ldap => ldap.GetTree()).then(root => {
         res.render("index", {
             tree: root.GetChildren()[0],
@@ -37,9 +35,10 @@ router.get('/', (req: express.Request, res: express.Response) => {
         });
     });
 });
+
 router.get('/home', (req, res) => {
-    if (!Security.requireLoggedUser(req, res))
-        return;
+    if (!req.isUserLogged)
+        return RouterUtils.Redirect(res, "/login");
     res.send("Hello, world");
 });
 

+ 2 - 5
routes/login.ts

@@ -10,12 +10,9 @@ const route_login = express.Router();
 const route_logout = express.Router();
 
 function ManageLogin(req: express.Request, res: express.Response, ldap: ILDAPManager|null, postData: { username: string, password: string }|null) {
+	if (req.isUserLogged)
+		return RouterUtils.Redirect(res, "/");
 	let session = Security.GetOrCreateSession(req);
-
-	if (session.IsLoggedIn()) {
-		RouterUtils.Redirect(res, "/");
-		return;
-	}
 	let prevUsername = session.GetPreviousUsername() || "";
 
 	if (postData && postData.username && postData.password && postData.username.length && postData.password.length && ldap) {

+ 9 - 1
src/LDAPSchema.ts

@@ -2,7 +2,7 @@ import { findSourceMap } from "node:module";
 import { markAsUntransferable } from "node:worker_threads";
 import { LDAPAttribute } from "./ConfigLoader";
 
-enum ClassType {
+export enum ClassType {
 	eUnknown,
 	eAbstract,
 	eStructural,
@@ -130,6 +130,10 @@ export class LDAPSchemaObjectClass extends LDAPSchemaItem {
 		return !!(Find(key, this.fMayAttributes.values()) || Find(key, this.fMustAttributes.values()));
 	}
 
+	public HasMust(attr: string): boolean {
+		return this.fMustAttributes.has(attr);
+	}
+
 	public ListAttributes(): string[] {
 		let result = new Array();
 		for (let [key, _] of this.fMustAttributes) result.push(key);
@@ -137,6 +141,10 @@ export class LDAPSchemaObjectClass extends LDAPSchemaItem {
 		return result;
 	}
 
+	public GetType(): ClassType {
+		return this.fType;
+	}
+
 	private fParent: string|null;
 	private fType: ClassType;
 	private fFinalized: boolean = false;

+ 3 - 7
src/Security.ts

@@ -84,6 +84,8 @@ class Security {
 	}
 
 	public IsUserLogged(req: express.Request): boolean {
+		if (req.isUserLogged !== undefined)
+			return req.isUserLogged;
 		let session = this.GetSession(req);
 		if (ConfigManager.GetInstance().GetNoLogin()) {
 			if (session === null)
@@ -94,13 +96,6 @@ class Security {
 		return session !== null && session.IsLoggedIn();
 	}
 
-	public requireLoggedUser(req: express.Request, res: express.Response) {
-		if (this.IsUserLogged(req))
-			return true;
-		RouterUtils.Redirect(res, "/login");
-		return false;
-	}
-
 	public TryLogin(ldap: ILDAPManager, username: string, password: string): Promise<string> {
 		return new Promise((ok, ko) => {
 			ldap.CheckLoginExists(username).then(userDn => {
@@ -119,4 +114,5 @@ class Security {
 	}
 }
 
+export { Session };
 export default new Security() as Security;

+ 2 - 2
src/ldapInterface.ts

@@ -115,7 +115,7 @@ class LDAPManager implements ILDAPManager {
 	public GetEntry(dn: string): Promise<Map<string, string[]>> {
 		return new Promise((ok, ko) => {
 			this.Search(dn, "sub").then(result => {
-				for (let [key, val] of result) {
+				for (let [_, val] of result) {
 					ok(val);
 					return;
 				}
@@ -153,7 +153,7 @@ class LDAPManager implements ILDAPManager {
 	}
 
 	public ListEntries(category: LDAPCategory): Promise<LDAPEntry[]> {
-		return new Promise((ok, ko) => {
+		return new Promise((ok, _) => {
 			this.Search(category.GetBaseDn(), category.GetScope(), category.GetFilter() || undefined, category.GetAttributes().map(i => i.mapped)).then(result => {
 				let userArray = new Array();
 				for (let [addr, val] of result)

+ 13 - 4
views/entity.pug

@@ -1,16 +1,25 @@
 extends layout
 
 block content
-  div(class="page")
+  script.
+    window['dn']="#{dn}";
+  div(id="entity-page",class="page",data-dn=dn)
     h1=dn
+    -id=0
     for className in classes
       fieldset(class="LDAPClass")
         legend
-          h3=className
+          h3=className+" (" +getType(className)+")"
         ul
           each valArr, key in attributes[className]
             for val in valArr
               li
                 label(class="LDAPAttribute")
-                  span=key
-                  input(type="text",value=val)
+                  -mandatory=isMandatory(key)
+                  span(class=mandatory ? "mandatory": "")=key
+                  input(type="text",value=val,data-initial-value=val,data-input-id=id,data-attribute-name=key,required=mandatory)
+                  -id++
+    fieldset(class="changes")
+      textarea(id="ldifOutput",readonly)
+      input(type="button",value="Submit")
+  script(src="../javascripts/entity.js")