major update
@ -1,17 +0,0 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "/schema/educations",
|
||||
"title": "Education diplomat",
|
||||
"description": "Training follow ",
|
||||
"type": "object",
|
||||
"properties":{
|
||||
"schoolname":{"type":"string"},
|
||||
"diploma":{"type":"string","enum":["BEPx","CAPy"]},
|
||||
"jobsector":{"type":"string","enum":["serveur"]},
|
||||
"dt_start":{"type":"string","format":"date"},
|
||||
"dt_end":{"type":"string","format":"date"},
|
||||
"description":{"type":"string"},
|
||||
"skills":{"type":"array","$ref":"schema/skills.json"}
|
||||
},
|
||||
"required":["jobsector","schoolname","diploma","dt_start","dt_end"]
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "/schema/experiences",
|
||||
"title": "Describe a professionnal experience",
|
||||
"description": "List of information to describe professional experiences",
|
||||
"type": "object",
|
||||
"properties":{
|
||||
"jobtitle":{"type":"string"},
|
||||
"contract":{"type":"string","enum":["CDI","CDD","FREE","STAGE","ALTERNANCE"]},
|
||||
"companyname":{"type":"string"},
|
||||
"location":{"type":"object","$ref":"https://schema.org/PostalAddress"},
|
||||
"remotexp":{"type":"string","enum":["onsite","remote","hybrid"]},
|
||||
"dt_start":{"type":"string","format":"date"},
|
||||
"dt_end":{"type":"string","format":"date"},
|
||||
"jobsector":{"type":"string","enum":[]},
|
||||
"description":{"type":"string"},
|
||||
"skills":{"type":"array","$ref":"schema/skills.json"}
|
||||
},
|
||||
"required":["jobtitle","companyname","contract"]
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
{
|
||||
"CDI":{"title":"Contrat à durée indeterninée","autreinfoutile":""},
|
||||
"CDD":{}
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
{
|
||||
"BEPx":{"title":"blabla","description":"blabla"}
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
{
|
||||
"serveur":{"title":"Serveur en salle"}
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
{
|
||||
"offerA": {
|
||||
"accessright": {
|
||||
"person": "O",
|
||||
"person.alias": "",
|
||||
"person.owner": "",
|
||||
"person.accessright": ""
|
||||
},
|
||||
"title":"Offre de lancement",
|
||||
"description":"txt blabla",
|
||||
"html":"<h1>Offre de lancement</h1> <p>blabla</p>",
|
||||
"priceHT":"19",
|
||||
"currency":"euro",
|
||||
"monthbillfrequency":"1"
|
||||
},
|
||||
"offerB": {
|
||||
"accessright": {
|
||||
"person": "O",
|
||||
"person.alias": "",
|
||||
"person.owner": "",
|
||||
"person.accessright": ""
|
||||
},
|
||||
"title":"Offre de lancement",
|
||||
"description":"txt blabla",
|
||||
"html":"<h1>Offre de lancement</h1> <p>blabla</p>",
|
||||
"priceHT":"49",
|
||||
"currency":"euro",
|
||||
"monthbillfrequency":"3"
|
||||
}
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
{
|
||||
"offerA": {
|
||||
"accessright": {
|
||||
"person": "O",
|
||||
"person.alias": "",
|
||||
"person.owner": "",
|
||||
"person.accessright": ""
|
||||
},
|
||||
"title":"Offre de lancement",
|
||||
"description":"txt blabla",
|
||||
"html":"<h1>Offre de lancement</h1> <p>blabla</p>",
|
||||
"priceHT":"19",
|
||||
"currency":"euro",
|
||||
"monthbillfrequency":"1"
|
||||
},
|
||||
"offerB": {
|
||||
"accessright": {
|
||||
"person": "O",
|
||||
"person.alias": "",
|
||||
"person.owner": "",
|
||||
"person.accessright": ""
|
||||
},
|
||||
"title":"Offre de lancement",
|
||||
"description":"txt blabla",
|
||||
"html":"<h1>Offre de lancement</h1> <p>blabla</p>",
|
||||
"priceHT":"49",
|
||||
"currency":"euro",
|
||||
"monthbillfrequency":"3"
|
||||
}
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
{
|
||||
"M": { "title": "Monsieur", "description": "" },
|
||||
"MME": { "title": "Madame", "description": "" },
|
||||
"OTHER": { "title": "Autre", "edescription": "" }
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
{
|
||||
"crit1":{"title":"critere1"}
|
||||
}
|
275
adminapi/schema/lg/httperror_en.json
Normal file
@ -0,0 +1,275 @@
|
||||
{
|
||||
"100": {
|
||||
"description": "Continue",
|
||||
"examples": [
|
||||
"Continue with the data transfer.",
|
||||
"You may proceed with the next part of the request.",
|
||||
"The server is ready for the next step in the request."
|
||||
]
|
||||
},
|
||||
"101": {
|
||||
"description": "Switching Protocols",
|
||||
"examples": [
|
||||
"The server is changing the protocol on the request.",
|
||||
"The protocol used for this request is being upgraded.",
|
||||
"Switching to a different communication protocol."
|
||||
]
|
||||
},
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"examples": [
|
||||
"The operation was successful.",
|
||||
"The request has been successfully completed.",
|
||||
"Everything is fine, and the request is successful."
|
||||
]
|
||||
},
|
||||
"201": {
|
||||
"description": "Created",
|
||||
"examples": [
|
||||
"A new resource has been successfully created.",
|
||||
"The request resulted in the creation of a new resource.",
|
||||
"Your request has led to the creation of a new item."
|
||||
]
|
||||
},
|
||||
"202": {
|
||||
"description": "Accepted",
|
||||
"examples": [
|
||||
"The request has been accepted for processing.",
|
||||
"Your request has been acknowledged and queued for processing.",
|
||||
"We've received your request and will take action."
|
||||
]
|
||||
},
|
||||
"204": {
|
||||
"description": "No Content",
|
||||
"examples": [
|
||||
"The request was successful, but there is no response body.",
|
||||
"Your request was processed, but there's nothing to show in the response.",
|
||||
"This request did not return any content."
|
||||
]
|
||||
},
|
||||
"206": {
|
||||
"description": "Partial Content",
|
||||
"examples": [
|
||||
"The server is returning part of the requested data.",
|
||||
"You requested a range of data, and we're sending a portion of it.",
|
||||
"Here's a partial response to your request."
|
||||
]
|
||||
},
|
||||
"300": {
|
||||
"description": "Multiple Choices",
|
||||
"examples": [
|
||||
"The request has multiple possible responses, and the user or client must choose one.",
|
||||
"We can fulfill your request in several ways. Please choose one.",
|
||||
"You have multiple options for the requested resource."
|
||||
]
|
||||
},
|
||||
"301": {
|
||||
"description": "Moved Permanently",
|
||||
"examples": [
|
||||
"The requested resource has permanently moved to a new location.",
|
||||
"This resource is no longer available here; it's moved to a new address.",
|
||||
"The URL you're looking for has been permanently redirected."
|
||||
]
|
||||
},
|
||||
"302": {
|
||||
"description": "Found",
|
||||
"examples": [
|
||||
"The requested resource is temporarily located at a different URL.",
|
||||
"You can find what you're looking for at a different address for now.",
|
||||
"The resource you want is temporarily located elsewhere."
|
||||
]
|
||||
},
|
||||
"304": {
|
||||
"description": "Not Modified",
|
||||
"examples": [
|
||||
"The requested resource has not been modified since the specified time.",
|
||||
"Your cached data is still up-to-date; there have been no changes.",
|
||||
"The server confirms that your data is current."
|
||||
]
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"examples": [
|
||||
"The request is malformed or invalid.",
|
||||
"Something is wrong with the request parameters.",
|
||||
"Your request does not meet the server's requirements."
|
||||
]
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized",
|
||||
"examples": [
|
||||
"Authentication is required, and the user or client failed to provide valid credentials.",
|
||||
"You must log in or provide valid credentials to access this resource.",
|
||||
"Access is restricted. Please provide valid authentication."
|
||||
]
|
||||
},
|
||||
"403": {
|
||||
"description": "Forbidden",
|
||||
"examples": [
|
||||
"Access to the requested resource is forbidden.",
|
||||
"You do not have permission to access this resource.",
|
||||
"Sorry, but you're not allowed to access this."
|
||||
]
|
||||
},
|
||||
"404": {
|
||||
"description": "Not Found",
|
||||
"examples": [
|
||||
"The requested resource does not exist on the server.",
|
||||
"The server could not find the page you're looking for.",
|
||||
"Sorry, but what you're searching for isn't here."
|
||||
]
|
||||
},
|
||||
"405": {
|
||||
"description": "Method Not Allowed",
|
||||
"examples": [
|
||||
"The HTTP method used in the request is not allowed for the requested resource.",
|
||||
"The server does not support the method you're trying to use.",
|
||||
"This resource does not allow the requested HTTP method."
|
||||
]
|
||||
},
|
||||
"406": {
|
||||
"description": "Not Acceptable",
|
||||
"examples": [
|
||||
"The requested resource cannot provide a response that is acceptable according to the request's headers.",
|
||||
"We cannot provide the response you expect based on your request headers.",
|
||||
"Sorry, but we can't fulfill your request as specified."
|
||||
]
|
||||
},
|
||||
"407": {
|
||||
"description": "Proxy Authentication Required",
|
||||
"examples": [
|
||||
"Authentication is required to access the requested resource via a proxy.",
|
||||
"To access this resource through a proxy, you must provide valid authentication.",
|
||||
"Please provide valid credentials for proxy access."
|
||||
]
|
||||
},
|
||||
"408": {
|
||||
"description": "Request Timeout",
|
||||
"examples": [
|
||||
"The server did not receive a complete request within the expected time.",
|
||||
"Your request took too long to arrive at the server.",
|
||||
"Sorry, your request has timed out."
|
||||
]
|
||||
},
|
||||
"409": {
|
||||
"description": "Conflict",
|
||||
"examples": [
|
||||
"The request could not be completed due to a conflict with the current state of the target resource.",
|
||||
"There's a conflict with the current state of the resource; please try again.",
|
||||
"Sorry, there's a conflict with the requested action."
|
||||
]
|
||||
},
|
||||
"410": {
|
||||
"description": "Gone",
|
||||
"examples": [
|
||||
"The requested resource is no longer available and has been intentionally removed.",
|
||||
"The resource you're looking for is gone and will not return.",
|
||||
"This resource has been permanently removed."
|
||||
]
|
||||
},
|
||||
"411": {
|
||||
"description": "Length Required",
|
||||
"examples": [
|
||||
"The server requires a content length to be specified in the request headers.",
|
||||
"Your request is missing a required content length header.",
|
||||
"Please include a 'Content-Length' header in your request."
|
||||
]
|
||||
},
|
||||
"412": {
|
||||
"description": "Precondition Failed",
|
||||
"examples": [
|
||||
"A precondition in the request headers was not met.",
|
||||
"The server expected certain conditions to be met, but they were not.",
|
||||
"Sorry, the required conditions were not fulfilled."
|
||||
]
|
||||
},
|
||||
"413": {
|
||||
"description": "Request Entity Too Large",
|
||||
"examples": [
|
||||
"The request entity is too large for the server to process.",
|
||||
"Your request body is too big for us to handle.",
|
||||
"Please reduce the size of your request entity."
|
||||
]
|
||||
},
|
||||
"414": {
|
||||
"description": "Request-URI Too Long",
|
||||
"examples": [
|
||||
"The URI provided in the request is too long for the server to process.",
|
||||
"The URL in your request is excessively long; please shorten it.",
|
||||
"The request URI you provided is too lengthy."
|
||||
]
|
||||
},
|
||||
"415": {
|
||||
"description": "Unsupported Media Type",
|
||||
"examples": [
|
||||
"The server cannot process the request because the media type is not supported.",
|
||||
"We cannot handle the content type you specified.",
|
||||
"Sorry, we do not support the requested media type."
|
||||
]
|
||||
},
|
||||
"416": {
|
||||
"description": "Requested Range Not Satisfiable",
|
||||
"examples": [
|
||||
"The requested range cannot be satisfied by the server.",
|
||||
"We cannot provide the content range you requested.",
|
||||
"Sorry, but we cannot fulfill the requested content range."
|
||||
]
|
||||
},
|
||||
"417": {
|
||||
"description": "Expectation Failed",
|
||||
"examples": [
|
||||
"The server could not meet the expectations specified in the request's Expect header.",
|
||||
"We were unable to fulfill the expectations you set in your request headers.",
|
||||
"Sorry, but we could not meet your expectations."
|
||||
]
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"examples": [
|
||||
"Something went wrong on the server's end.",
|
||||
"We apologize, but an unexpected error occurred.",
|
||||
"The server is currently experiencing technical difficulties."
|
||||
]
|
||||
},
|
||||
"501": {
|
||||
"description": "Not Implemented",
|
||||
"examples": [
|
||||
"The server does not support the functionality required to fulfill the request.",
|
||||
"Sorry, but the requested functionality is not available on this server.",
|
||||
"We have not implemented the feature you're looking for."
|
||||
]
|
||||
},
|
||||
"502": {
|
||||
"description": "Bad Gateway",
|
||||
"examples": [
|
||||
"The server acting as a gateway or proxy received an invalid response from the upstream server.",
|
||||
"The gateway or proxy received an unexpected response from the upstream server.",
|
||||
"Sorry, there's an issue with the gateway or proxy."
|
||||
]
|
||||
},
|
||||
"503": {
|
||||
"description": "Service Unavailable",
|
||||
"examples": [
|
||||
"The server is temporarily unavailable to handle the request.",
|
||||
"We're currently unavailable due to maintenance; please try again later.",
|
||||
"Sorry, the service is not available right now."
|
||||
]
|
||||
},
|
||||
"504": {
|
||||
"description": "Gateway Timeout",
|
||||
"examples": [
|
||||
"The server acting as a gateway or proxy did not receive a timely response from the upstream server.",
|
||||
"We're experiencing a timeout while waiting for the upstream server.",
|
||||
"Sorry, but there's a timeout issue with the gateway."
|
||||
]
|
||||
},
|
||||
"505": {
|
||||
"description": "HTTP Version Not Supported",
|
||||
"examples": [
|
||||
"The HTTP version used in the request is not supported by the server.",
|
||||
"Your client is using an unsupported HTTP version; please update.",
|
||||
"Sorry, but we do not support the HTTP version used in your request."
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +0,0 @@
|
||||
{
|
||||
"title": "Une Personne au niveau d'une tribut avec des informations personnelle",
|
||||
"description": "Un alias peut se stoquer comme un objet Person avec des informations supplémentaire permettant de qualifier son profil",
|
||||
"properties": {
|
||||
"alias": {"title":"Une identité numérique d'apxtrib"},
|
||||
"dt_create": {"title":"Date de creation de cette personne"},
|
||||
"dt_update": { "title":"Date de derniére mise à jour"},
|
||||
"dt_lastlogin": { "title":"Date de derniere authentification" },
|
||||
"dt_close": { "title": "Date de fermeture de compte" },
|
||||
"recoveryauth":{"title":"Information pour recuperer ses codes d'accès"},
|
||||
"biography": {"title":"Description courte"},
|
||||
"imgavatar": {"title":"Url de l'image utilisée comme avatar"},
|
||||
"accessrights": {"title":"Droits d'accès"}
|
||||
}
|
||||
}
|
25
adminapi/schema/lg/persons_fr.json
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
"title": "Une Personne au niveau d'une tribut avec des informations personnelle",
|
||||
"description": "Un alias peut se stoquer comme un objet Person avec des informations supplémentaire permettant de qualifier son profil",
|
||||
"properties": {
|
||||
"alias": { "title": "Une identité numérique d'apxtrib" },
|
||||
"dt_create": { "title": "Date de creation de cette personne" },
|
||||
"dt_update": { "title": "Date de derniére mise à jour" },
|
||||
"dt_lastlogin": { "title": "Date de derniere authentification" },
|
||||
"dt_close": { "title": "Date de fermeture de compte" },
|
||||
"recoveryauth": {
|
||||
"title": "Information pour recuperer ses codes d'accès",
|
||||
"properties": {
|
||||
"email": { "title": "email de recuperation" },
|
||||
"alias": {
|
||||
"title": "Alias qui doit exister comme une Person dans une tribu"
|
||||
},
|
||||
"privatekey": { "title": "Private key link to alias" },
|
||||
"passphrase": { "title": "Passphrase to uncipher privatekey" }
|
||||
}
|
||||
},
|
||||
"biography": { "title": "Description courte" },
|
||||
"imgavatar": { "title": "Url de l'image utilisée comme avatar" },
|
||||
"accessrights": { "title": "Droits d'accès" }
|
||||
}
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
{
|
||||
"title": "Contiens la cle privée avec un email de recovery",
|
||||
"description": "Cs trouve au niveau d'une person (sous la responsabilité d'une tribut et permet pour un alias de recevoir par email une clé privée",
|
||||
"properties":{
|
||||
"email": { "title":"email de recuperation" },
|
||||
"alias": {"title": "Alias qui doit exister comme une Person dans une tribu"},
|
||||
"privatekey": { "title": "Private key link to alias" },
|
||||
"passphrase": {"title":"Passphrase to uncipher privatekey"}
|
||||
}
|
||||
}
|
@ -27,8 +27,12 @@
|
||||
},
|
||||
"required": ["nationId", "dtcreate","contracts"],
|
||||
"additionalProperties":false,
|
||||
"apxprimarykey":["nationId"],
|
||||
"apxid":"nationId",
|
||||
"apxuniquekey":["nationId"],
|
||||
"apxsearchindex": [
|
||||
{ "key": "nationId", "value": [] }
|
||||
]
|
||||
{ "name":"lst_nationId", "keyval": "nationId"}
|
||||
],
|
||||
"apxaccessrights":{
|
||||
"pagan":{"C":[],"R":[]}
|
||||
}
|
||||
}
|
||||
|
@ -9,21 +9,37 @@
|
||||
"title": "Alias's publickey",
|
||||
"description": "Public key generate with openpgp.js",
|
||||
"type": "string",
|
||||
"format": "pgpAE256"
|
||||
"format": "pgppublickey"
|
||||
},
|
||||
"alias": {
|
||||
"title": "Alias",
|
||||
"description": "text to remember easiky a public key",
|
||||
"description": "text to remember easily a public key",
|
||||
"type": "string",
|
||||
"minLength": 5,
|
||||
"minLength": 4,
|
||||
"pattern": "^[a-z0-9]*$"
|
||||
},
|
||||
"dt_delete": {
|
||||
"title": "Date of death",
|
||||
"description": "Date of alias delete request, your will will be apply",
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"will": {
|
||||
"title": "Will script after death",
|
||||
"description": "This will script will be apply on your data 30 days after your death",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["publickey", "alias"],
|
||||
"apxprimarykey": ["alias"],
|
||||
"apxsecondarykey": ["publickey"],
|
||||
"apxsearchindex": [
|
||||
{ "key": "alias", "val": "publickey" },
|
||||
{ "key": "publickey", "val": "alias" }
|
||||
]
|
||||
"apxid": "alias",
|
||||
"apxuniquekey": ["publickey"],
|
||||
"apxidx": [
|
||||
{ "name": "lst_alias", "keyval": "alias" },
|
||||
{ "name": "alias", "keyval": "alias" }
|
||||
],
|
||||
"apxaccessrights": {
|
||||
"owner": { "R": [], "D": [] },
|
||||
"anonymous": { "C": [], "R": ["alias"] },
|
||||
"pagan": { "R": ["alias", "publickey"] }
|
||||
}
|
||||
}
|
||||
|
@ -33,17 +33,39 @@
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"dt_close": {
|
||||
"dt_delete": {
|
||||
"title": "Date of leaving tribe",
|
||||
"description": "Date from when this alias is ban of tribe by druid or want to leave. A pocess of data cleaning has to be run depending of Tribe's rules.",
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
"format": "date"
|
||||
},
|
||||
"will": {
|
||||
"title": "Will script after leaving tribe",
|
||||
"description": "This will script will be apply on your data 30 days after your delete",
|
||||
"type": "string",
|
||||
"format": "js"
|
||||
},
|
||||
"recoveryauth": {
|
||||
"title": "Store numeric identity to recover it by email",
|
||||
"description": "This object store numeric identity alias with an email mainly used at Person level to recover by email a private and passphrase key associate to alias",
|
||||
"type": "object",
|
||||
"$ref": "#/definitions/recoveryauth"
|
||||
"properties": {
|
||||
"email": {
|
||||
"type": "string",
|
||||
"format": "email"
|
||||
},
|
||||
"privatekey": {
|
||||
"type": "string",
|
||||
"format": "pgpprivatekey"
|
||||
},
|
||||
"publickey": {
|
||||
"type": "string",
|
||||
"format": "pgppublickey"
|
||||
},
|
||||
"passphrase": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"firstname": {
|
||||
"title": "A firstname",
|
||||
@ -65,7 +87,7 @@
|
||||
"title": "Your pronom",
|
||||
"description": "The way you want people communicate with you",
|
||||
"type": "string",
|
||||
"enum": ["M", "MME", "OTHER"]
|
||||
"enum": ["0", "1", "2"]
|
||||
},
|
||||
"emailcom": {
|
||||
"title": "email use to communicate with you",
|
||||
@ -73,55 +95,100 @@
|
||||
"type": "string",
|
||||
"format": "email"
|
||||
},
|
||||
"hobbies": {
|
||||
"title": "My hobbies",
|
||||
"type": "array",
|
||||
"comment": "from a tree word combinaison /lg/hobbies_xx.json"
|
||||
},
|
||||
"biography": {
|
||||
"title":"Your bio or few words to define yoursel",
|
||||
"description":"Use this to share your values, this will be public to all of tribe's members and link to your person",
|
||||
"title": "Your bio or few words to define yourself",
|
||||
"description": "Use this to share your values, this will be public to all of tribe's members and link to your person",
|
||||
"type": "string",
|
||||
"pattern": "^.{O,150}$"
|
||||
},
|
||||
"mbti": {
|
||||
"type": "object"
|
||||
},
|
||||
"imgavatar": {
|
||||
"title":"A picture of your person or personnality",
|
||||
"description":"This picture will be public to all tribe's member",
|
||||
"title": "A picture of your person or personnality",
|
||||
"description": "This picture will be public to all tribe's member",
|
||||
"type": "url"
|
||||
},
|
||||
"accessrights": {
|
||||
"title": "Accessright per Object or per Object.key belonging to a tribe",
|
||||
"description": "A Person can create read update delete an object (CRUD), if Own means if owner = alias of user requested some CRUD action to owner then he can act on this object or object.key List of Object with CRUDO value like {Person:'RUDO','Person.recoveryauth':'O',...}. To simplify some profil can be define admin, user, recruiter, seeker, and get a standard accessright object",
|
||||
"type": "object",
|
||||
"$ref": "#/definitions/accessright"
|
||||
"profils": {
|
||||
"title": "Array of profil",
|
||||
"description": "List of profil to get accessright on object",
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"recoveryauth": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"email": { "type": "string", "format": "email" },
|
||||
"alias": { "type": "string", "format": "Pagan" },
|
||||
"privatekey": { "type": "string", "format": "eccCorve25519armored" }
|
||||
}
|
||||
},
|
||||
"accessright":{
|
||||
"type":"object",
|
||||
"properties":{
|
||||
"type":"object",
|
||||
"properties":{
|
||||
"objkey": {"type":"sring","format":"CRUDO"}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["alias", "accessright"],
|
||||
"required": ["alias", "profilaccess"],
|
||||
"additionalProperties": true,
|
||||
"apxprimarykey": "alias",
|
||||
"apxunique": [""],
|
||||
"apxsearchindex": [
|
||||
"apxid": "alias",
|
||||
"apxuniquekey": ["alias"],
|
||||
"apxidx": [
|
||||
{
|
||||
"key": "alias",
|
||||
"value": []
|
||||
"name": "lst_alias",
|
||||
"keyval": "alias"
|
||||
},
|
||||
{
|
||||
"key": "recovery.email",
|
||||
"value": "alias"
|
||||
"name": "alias",
|
||||
"keyval": "alias"
|
||||
},
|
||||
{
|
||||
"name": "profils_alias",
|
||||
"keyval": "profils",
|
||||
"objkey": "alias"
|
||||
},
|
||||
{
|
||||
"name": "emailcom_alias",
|
||||
"keyval": "emailcom",
|
||||
"objkey": "alias"
|
||||
},
|
||||
{
|
||||
"name": "hobbies_alias",
|
||||
"keyval": "hobbies",
|
||||
"objkey": "alias"
|
||||
}
|
||||
]
|
||||
],
|
||||
"apxaccessrights": {
|
||||
"owner": {
|
||||
"D": [],
|
||||
"R": [
|
||||
"alias",
|
||||
"dt_create",
|
||||
"dt_update",
|
||||
"last_login",
|
||||
"firstname",
|
||||
"lastname",
|
||||
"dt_birth",
|
||||
"pronom",
|
||||
"emailcom",
|
||||
"hobies",
|
||||
"biography",
|
||||
"imgavatar",
|
||||
"profilaccess"
|
||||
],
|
||||
"U": [
|
||||
"firstname",
|
||||
"lastname",
|
||||
"dt_birth",
|
||||
"pronom",
|
||||
"emailcom",
|
||||
"hobies",
|
||||
"biography",
|
||||
"imgavatar",
|
||||
"profilaccess"
|
||||
]
|
||||
},
|
||||
"pagan": {
|
||||
"C": []
|
||||
},
|
||||
"mayor": {
|
||||
"D": [],
|
||||
"R": ["alias"]
|
||||
},
|
||||
"druid": {
|
||||
"D": [],
|
||||
"R": ["alias"]
|
||||
}
|
||||
}
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "/schema/person",
|
||||
"title": "Person minimum definition to link a person to a pagan identity",
|
||||
"description": "A person is a human with a apxtrib identity (Public Private Key. Information stored (not cipher) for a person are only visible from the town's Mayor and the tribe's Druid. You need at least trus the druid that trust the mayor (for sensitive data Mayor and Druid can be the same apx Identity.) Only a pagan that have the privateKey can read cipher data. The purpose of this sschema is to link a person to a tribe and manage basic activities, profil will be a tribe object if need more personnal information",
|
||||
"type": "object",
|
||||
"properties": {}
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "/schema/seeker",
|
||||
"title": "Data Profil of a person that is in a seek process",
|
||||
"description": "All those data have to store any useffull logistical data and profil about a seeker (skill, ...) ",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"offerseeker": { "type": "string", "emum": ["offerA", "offerB"] },
|
||||
"emailseek": { "type": "string", "format": "email" },
|
||||
"seeklocation": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"$ref": "https://schema.org/PostalAddress"
|
||||
}
|
||||
},
|
||||
"seekcriterias": {
|
||||
"type": "array",
|
||||
"items": { "type": "string", "enum": [] }
|
||||
},
|
||||
"skills": {
|
||||
"type": "array",
|
||||
"items": { "type": "object", "$ref": "schema/skills.json" }
|
||||
},
|
||||
"educations": {
|
||||
"type": "array",
|
||||
"items": { "type": "object", "$ref": "schema/educations.json" }
|
||||
},
|
||||
"experiences": {
|
||||
"type": "array",
|
||||
"items": { "type": "object", "$ref": "schema/experiences.json" }
|
||||
},
|
||||
"recommandation": {
|
||||
"type": "array",
|
||||
"items": { "type": "object", "$ref": "#/definitions/recommandation"}
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"recommandation": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"email": { "type": "string", "format": "email" },
|
||||
"phone": { "type": "string", "format": "telephone" },
|
||||
"fisrtname": { "type": "string" },
|
||||
"lastname": { "type": "string" },
|
||||
"jobtitle": { "type": "string" },
|
||||
"description": {
|
||||
"title": "Area of recomandation",
|
||||
"description": "Describe why this recommandation is relevant to confirm your skills",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["offerseeker", "emailseek", "mainlivinglocation", ""]
|
||||
}
|
@ -11,11 +11,16 @@
|
||||
},
|
||||
"nationId": {
|
||||
"type": "string",
|
||||
"$apxenumkey": "socialworld/objects/nations/searchindex/nations_uuid_uuid.json"
|
||||
"$apxenumkey": "nationchains/nations/idx/lst_nationd.json"
|
||||
},
|
||||
"owner":{
|
||||
"type": "string",
|
||||
"$apxenumkey": "nationchains/pagans/idx/lst_alias.json"
|
||||
},
|
||||
"mayorId": {
|
||||
"comment":"todo, to be remove by ower in models",
|
||||
"type": "string",
|
||||
"$apxenumkey": "socialworld/objects/nations/searchindex/nations_uuid_uuid.json"
|
||||
"$apxenumkey": "nationchains/pagans/idx/lst_alias.json"
|
||||
},
|
||||
"status": {
|
||||
"default": "active",
|
||||
@ -27,10 +32,16 @@
|
||||
}
|
||||
},
|
||||
"required": ["townId", "status", "nationId", "dns"],
|
||||
"apxprimarykey": "townId",
|
||||
"apxsearchindex": [
|
||||
{ "key": "status", "value": "townId" },
|
||||
{ "key": "nationId", "value": "townId" },
|
||||
{ "key": "townId", "value": [] }
|
||||
]
|
||||
"apxid":"townId",
|
||||
"apxuniquekey": ["townId","dns"],
|
||||
"apxidx": [
|
||||
{ "name":"lst_townId", "keyval": "townId" },
|
||||
{ "name":"all_townId", "keyval": "townId" },
|
||||
{ "name":"dns_townId", "keyval": "dns","objkey":["townId"] },
|
||||
{ "name":"mayorId_townId", "keyval": "mayorId","objkey":["townId"] }
|
||||
],
|
||||
"apxaccessrights":{
|
||||
"pagan":{"C":[],"R":[]},
|
||||
"owner":{"D":[], "U":["owner","status"]}
|
||||
}
|
||||
}
|
@ -11,26 +11,33 @@
|
||||
},
|
||||
"townId": {
|
||||
"type": "string",
|
||||
"$ref": "nationchains/towns/idx/towns_uuid_uuid.json"
|
||||
"$apxenumkey": "nationchains/towns/idx/lst_townId.json"
|
||||
},
|
||||
"nationId": {
|
||||
"type": "string",
|
||||
"$ref": "nationchains/nations/idx/nations_uuid_uuid.json"
|
||||
"$apxenumkey": "nationchains/nations/idx/lst_nationId.json"
|
||||
},
|
||||
"druidId": {
|
||||
"owner": {
|
||||
"type": "string",
|
||||
"$ref": "nationchains/pagans/idx/alias_all.json"
|
||||
"$apxenumkey": "nationchains/pagans/idx/lst_alias.json"
|
||||
},
|
||||
"dns": {
|
||||
"type": "array",
|
||||
"items":{"type":"string", "uniqueItems":true}
|
||||
|
||||
"items":{"type":"string"}
|
||||
}
|
||||
},
|
||||
"required": ["townId", "status", "nationId", "dns"],
|
||||
"apxprimarykey": ["tribeId"],
|
||||
"apxsearchindex": [
|
||||
{ "key": "status", "value": "tribeId" },
|
||||
{ "key": "tribeId", "value": [] }
|
||||
]
|
||||
"apxid":"tribeId",
|
||||
"apxuniquekey": ["tribeId"],
|
||||
"apxidx": [
|
||||
{ "name":"lst_tribeId", "keyval": "tribeId" },
|
||||
{ "name":"all_tribeId", "keyval": "tribeId" },
|
||||
{ "name":"druidId_tribeId", "keyval": "druidId","objkey":["tribeId"] },
|
||||
{ "name":"dns_tribeId", "keyval": "dns","objkey":["tribeId"] }
|
||||
],
|
||||
"apxacceesrights":{
|
||||
"owner":{"D":[],"U":["owner","dns"]},
|
||||
"mayor":{"C":[],"R":[]},
|
||||
"pagan":{"R":[]}
|
||||
}
|
||||
}
|
||||
|
@ -1,45 +1,43 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "nationchains/schema/www",
|
||||
"title": "Town",
|
||||
"description": "A pace web available for a domaine, with accessright",
|
||||
"title": "www",
|
||||
"description": "A space web available for a domaine, with accessright",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"townId": {
|
||||
"description": "|Towns|townnamedesc",
|
||||
"desclong": "|Townss|townnamedesclong",
|
||||
"info": "|Towns|townnameinfo",
|
||||
"tribeId": {
|
||||
"title":"Tribe name",
|
||||
"description": "A unique string as tribe",
|
||||
"type": "string",
|
||||
"pattern":"^[a-z0-9]*$"
|
||||
},
|
||||
"nationId": {
|
||||
"description": "|Towns|nationdesc",
|
||||
"desclong": "|Townss|nationdesclong",
|
||||
"website": {
|
||||
"description": "Folder name into a tribeId/www/",
|
||||
"title":"web space",
|
||||
"type": "string",
|
||||
"$apxenumkey": "socialworld/objects/nations/searchindex/nations_uuid_uuid.json"
|
||||
},
|
||||
"status": {
|
||||
"desc": "|Towns|statusdesc",
|
||||
"title":"Status",
|
||||
"description": "Status of website ",
|
||||
"default": "active",
|
||||
"type": "string",
|
||||
"$apxenumkey": "data",
|
||||
"data": {
|
||||
"chain": { "desc": "|Towns|statuschain" },
|
||||
"tochain": { "desc": "|Towns|statustosync" },
|
||||
"unchain": { "desc": "|Towns|statusunchain" }
|
||||
}
|
||||
"enum": ["chain","tochain","unchain"]
|
||||
},
|
||||
"url": {
|
||||
"desc": "|Towns|urldesc",
|
||||
"title":"url of website",
|
||||
"description": "Must be set in domaine name to the apxtrib",
|
||||
"type": "string",
|
||||
"apxtype":"url"
|
||||
"format":"url"
|
||||
}
|
||||
},
|
||||
"required": ["townId", "status", "nationId", "url"],
|
||||
"apxprimarykey": "townId",
|
||||
"apxsearchindex": [
|
||||
{ "key": "status", "value": "townId" },
|
||||
{ "key": "nationId", "value": "townId" },
|
||||
{ "key": "townId", "value": [] }
|
||||
]
|
||||
"required": ["tribeId","website", "status"],
|
||||
"apxid": "website",
|
||||
"apxidx": [
|
||||
{ "name":"lst_website","keyval": "website"}
|
||||
],
|
||||
"apxaccessrights":{
|
||||
"owner":{"D":[],"R":[],"U":[]},
|
||||
"mayor":{"C":[]},
|
||||
"person":{"R":[]}
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@
|
||||
"api": {
|
||||
"port": 3020,
|
||||
"languages": ["en", "fr"],
|
||||
"exposedHeaders": ["xdays", "xhash", "xalias", "xlang", "xtribe", "xapp"],
|
||||
"exposedHeaders": ["xdays", "xhash", "xalias", "xlang", "xtribe", "xapp","xuuid"],
|
||||
"nationObjects": [
|
||||
"schema",
|
||||
"blocks",
|
||||
|
@ -1,6 +1,6 @@
|
||||
user {{{sudoerUser}}};
|
||||
worker_processes auto;
|
||||
error_log {{{ }}}/var/log/nginx/error.log notice;
|
||||
error_log /var/log/nginx/error.log notice;
|
||||
pid /var/run/nginx.pid;
|
||||
#include /etc/nginx/modules-enabled/*.conf;
|
||||
|
||||
@ -15,16 +15,26 @@ http {
|
||||
'"$http_user_agent"';
|
||||
|
||||
log_format mainold '$remote_addr - $remote_user [$time_local] "$request" '
|
||||
'$status $body_bytes_sent "$http_referer" '
|
||||
'"$http_user_agent" "$http_x_forwarded_for"';
|
||||
log_format trace '$remote_addr - $remote_user [$time_local] '
|
||||
'$host "$request" $status $body_bytes_sent '
|
||||
'"$http_referer" "$http_user_agent" '
|
||||
'"$http_x_forwarded_for" $request_id';
|
||||
access_log /var/log/nginx/access.log main;
|
||||
'$status $body_bytes_sent "$http_referer" '
|
||||
'"$http_user_agent" "$http_x_forwarded_for"';
|
||||
|
||||
log_format track escape=json '{"time":"$time_iso8601","alias":"$sent_http_xalias","uuid":"$sent_http_xuuid",'
|
||||
'"lg":"$sent_http_xlang","consentcookie":"$sent_http_consentcookie",'
|
||||
'"request_filename":"$request_filename","request":"$request",'
|
||||
'"args":"$args","remoteaddr":"$remote_addr","httpxforwardedfor":"$http_x_forwarded_for",'
|
||||
'"httpreferer":"$http_referer","httpuseragent":"$http_user_agent"}';
|
||||
|
||||
#access_log /var/log/nginx/access.log main;
|
||||
sendfile on;
|
||||
keepalive_timeout 65;
|
||||
gzip on;
|
||||
gzip on;
|
||||
gzip_vary on;
|
||||
gzip_proxied any;
|
||||
gzip_comp_level 6;
|
||||
gzip_buffers 4 32k;
|
||||
gzip_http_version 1.1;
|
||||
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/x-font-ttf application/javascript font/eot font/opentype image/svg+xml image/x-icon text/plain;
|
||||
|
||||
##
|
||||
# Virtual Host Configs
|
||||
##
|
||||
|
@ -2,10 +2,22 @@ server {
|
||||
server_name {{#dns}} {{.}} {{/dns}};
|
||||
access_log {{{nginx.logs}}}.access.log main;
|
||||
|
||||
location ~* /trk/ {
|
||||
access_log {{{nginx.logs}}}.trk.log track;
|
||||
if ( $uri ~ ^/trk/redirect ){
|
||||
return 301 $arg_url;
|
||||
}
|
||||
rewrite ^/trk/(.*)$ /$1;
|
||||
}
|
||||
|
||||
location ~* /nationchains/(blocks|pagans|towns|nations)/ {
|
||||
# Warning: never add tribes for keeping it private
|
||||
root {{{dirapi}}}/;
|
||||
}
|
||||
location ~* /nationchains/models/ {
|
||||
rewrite /nationchains/models/(.*$) /$1 break;
|
||||
root {{{dirapi}}}/api/models/lg/;
|
||||
}
|
||||
location ~* /nationchains/schema/ {
|
||||
#outside of nationchains for git purpose
|
||||
rewrite /nationchains/schema/(.*$) /$1 break;
|
||||
@ -23,8 +35,10 @@ return 403 "No valid token access for plugin:$arg_plugin with token:$arg_plugink
|
||||
}
|
||||
|
||||
location /cdn/ {
|
||||
rewrite /cdn/(.*$) /$1 break;
|
||||
root {{{nginx.fswww}}}/cdn/;
|
||||
expires 1y;
|
||||
add_header Cache-Control "public";
|
||||
rewrite /cdn/(.*$) /$1 break;
|
||||
root {{{nginx.fswww}}}/cdn/;
|
||||
}
|
||||
|
||||
location /spacedev/ {
|
||||
@ -38,6 +52,13 @@ proxy_pass http://localhost:{{{api.port}}};
|
||||
proxy_redirect off;
|
||||
include proxy_params;
|
||||
}
|
||||
|
||||
location /apxwebapp/ {
|
||||
rewrite /apxwebapp/(.*$) /$1 break;
|
||||
root {{{dirapxwebapp}}}/apxwebapp/;
|
||||
index index.html index_en.html;
|
||||
}
|
||||
|
||||
#to add htpasswd install apache2-utils => sudo htpasswd -c dirtown/tribes/tribeId/.htpasswd loginname passwd see man for
|
||||
option
|
||||
|
||||
|
@ -47,7 +47,7 @@ pagans.generateKey = async (alias, passphrase) => {
|
||||
// check alias does not exist
|
||||
return { alias, privateKey, publicKey };
|
||||
};
|
||||
pagans.detachedSignature = async (pubK, privK, passphrase, message) => {
|
||||
pagans.detachedSignatureold = async (pubK, privK, passphrase, message) => {
|
||||
/**
|
||||
* @pubK {string} a text public key
|
||||
* @privK {string} a test priv key
|
||||
@ -75,6 +75,43 @@ pagans.detachedSignature = async (pubK, privK, passphrase, message) => {
|
||||
});
|
||||
return btoa(sig);
|
||||
};
|
||||
|
||||
pagans.detachedSignature = async (pubK, privK, passphrase, message) => {
|
||||
/**
|
||||
* @pubK {string} a text public key
|
||||
* @privK {string} a test priv key
|
||||
* @passphrase {string} used to read privK
|
||||
* @message {string} message to sign
|
||||
* @Return a detached Signature of the message
|
||||
*/
|
||||
//const publicKey = await openpgp.readKey({ armoredKey: pubK });
|
||||
//as sup inutile
|
||||
/*privK=`-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||||
|
||||
xVgEZPB0MhYJKwYBBAHaRw8BAQdAV9XVko619o1DbLQRvuopr5/UN3Eao+vo
|
||||
H8Z+nftq/2kAAP0XKCgHb46kEBUDveaOX19hixOxz1l4fpL3CuFJYELU9A8Y
|
||||
zQDCjAQQFgoAPgWCZPB0MgQLCQcICZConW0nymKQ3QMVCAoEFgACAQIZAQKb
|
||||
AwIeARYhBAlofmCeHwmJsSeGiKidbSfKYpDdAADNpQD/ZZ9WGtKXuenB5xcf
|
||||
+JuoHWxVY4X6GT6l8MOHf+vadbgA/0zRayyRzrC5DcWpYomDSaqub6tw6iHS
|
||||
BJ89N/QYTksPx10EZPB0MhIKKwYBBAGXVQEFAQEHQN+OUc24uVrr9g83fJvN
|
||||
ZPbyEg7kdYus3VL8vyLnhVY6AwEIBwAA/1SwFdlBE/pC7I2TB/RFVFUvSEBu
|
||||
MueDhdccgUm1Q5P4D/zCeAQYFggAKgWCZPB0MgmQqJ1tJ8pikN0CmwwWIQQJ
|
||||
aH5gnh8JibEnhoionW0nymKQ3QAAOSsBANkvznf3EaEtGrPH0tUOnRLsCwTf
|
||||
BwaCFNom9YsHOmY8AP9XJmgIH+AS3tWp1nIB9yXLpfiKlWDreYI28iiqlM31
|
||||
AQ==
|
||||
=DOoD
|
||||
-----END PGP PRIVATE KEY BLOCK-----`;*/
|
||||
const privateKey = await openpgp.readKey({ armoredKey: privK,passphrase:passphrase });
|
||||
console.log(message);
|
||||
const {data:cleartextMessage} = await apenpgp.sign({
|
||||
message:openpgp.cleartext.fromText(message),
|
||||
privateKeys:[privateKey]
|
||||
})
|
||||
console.log('signed')
|
||||
console.log(cleartextMessage)
|
||||
return cleartextMessage;
|
||||
};
|
||||
|
||||
pagans.authenticatedetachedSignature = async (
|
||||
alias,
|
||||
pubK,
|
||||
|
After Width: | Height: | Size: 2.9 KiB |
12
adminapi/www/cdn/chartegraphique/color/colorcode.txt
Normal file
@ -0,0 +1,12 @@
|
||||
apXtrib color
|
||||
|
||||
https://www.color-hex.com/color-palette/16308
|
||||
|
||||
|
||||
Hex RGB
|
||||
nation jaune #ffc332 (255,195,50)
|
||||
town orange #fa6a31 (250,106,49)
|
||||
pagan bleue #2e7fc8 (46,127,200)
|
||||
tribut vert #6aa84f (106,168,79)
|
||||
vert fonce #218787 (33,135,135)
|
||||
|
93
adminapi/www/cdn/chartegraphique/fonts/logo/OFL.txt
Normal file
@ -0,0 +1,93 @@
|
||||
Copyright 2011 The Quicksand Project Authors (https://github.com/andrew-paglinawan/QuicksandFamily), with Reserved Font Name “Quicksand”.
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
BIN
adminapi/www/cdn/chartegraphique/fonts/logo/Quicksand.zip
Normal file
67
adminapi/www/cdn/chartegraphique/fonts/logo/README.txt
Normal file
@ -0,0 +1,67 @@
|
||||
Quicksand Variable Font
|
||||
=======================
|
||||
|
||||
This download contains Quicksand as both a variable font and static fonts.
|
||||
|
||||
Quicksand is a variable font with this axis:
|
||||
wght
|
||||
|
||||
This means all the styles are contained in a single file:
|
||||
Quicksand-VariableFont_wght.ttf
|
||||
|
||||
If your app fully supports variable fonts, you can now pick intermediate styles
|
||||
that aren’t available as static fonts. Not all apps support variable fonts, and
|
||||
in those cases you can use the static font files for Quicksand:
|
||||
static/Quicksand-Light.ttf
|
||||
static/Quicksand-Regular.ttf
|
||||
static/Quicksand-Medium.ttf
|
||||
static/Quicksand-SemiBold.ttf
|
||||
static/Quicksand-Bold.ttf
|
||||
|
||||
Get started
|
||||
-----------
|
||||
|
||||
1. Install the font files you want to use
|
||||
|
||||
2. Use your app's font picker to view the font family and all the
|
||||
available styles
|
||||
|
||||
Learn more about variable fonts
|
||||
-------------------------------
|
||||
|
||||
https://developers.google.com/web/fundamentals/design-and-ux/typography/variable-fonts
|
||||
https://variablefonts.typenetwork.com
|
||||
https://medium.com/variable-fonts
|
||||
|
||||
In desktop apps
|
||||
|
||||
https://theblog.adobe.com/can-variable-fonts-illustrator-cc
|
||||
https://helpx.adobe.com/nz/photoshop/using/fonts.html#variable_fonts
|
||||
|
||||
Online
|
||||
|
||||
https://developers.google.com/fonts/docs/getting_started
|
||||
https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Fonts/Variable_Fonts_Guide
|
||||
https://developer.microsoft.com/en-us/microsoft-edge/testdrive/demos/variable-fonts
|
||||
|
||||
Installing fonts
|
||||
|
||||
MacOS: https://support.apple.com/en-us/HT201749
|
||||
Linux: https://www.google.com/search?q=how+to+install+a+font+on+gnu%2Blinux
|
||||
Windows: https://support.microsoft.com/en-us/help/314960/how-to-install-or-remove-a-font-in-windows
|
||||
|
||||
Android Apps
|
||||
|
||||
https://developers.google.com/fonts/docs/android
|
||||
https://developer.android.com/guide/topics/ui/look-and-feel/downloadable-fonts
|
||||
|
||||
License
|
||||
-------
|
||||
Please read the full license text (OFL.txt) to understand the permissions,
|
||||
restrictions and requirements for usage, redistribution, and modification.
|
||||
|
||||
You can use them in your products & projects – print or digital,
|
||||
commercial or otherwise.
|
||||
|
||||
This isn't legal advice, please consider consulting a lawyer and see the full
|
||||
license for all details.
|
93
adminapi/www/cdn/chartegraphique/fonts/texte/OFL.txt
Normal file
@ -0,0 +1,93 @@
|
||||
Copyright 2011 The Questrial Project Authors (https://github.com/googlefonts/questrial)
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
BIN
adminapi/www/cdn/chartegraphique/fonts/texte/Questrial.zip
Normal file
@ -0,0 +1,5 @@
|
||||
# Font Squirrel Font-face Generator Configuration File
|
||||
# Upload this file to the generator to recreate the settings
|
||||
# you used to create these fonts.
|
||||
|
||||
{"mode":"optimal","formats":["woff","woff2"],"tt_instructor":"default","fix_gasp":"xy","fix_vertical_metrics":"Y","metrics_ascent":"","metrics_descent":"","metrics_linegap":"","add_spaces":"Y","add_hyphens":"Y","fallback":"none","fallback_custom":"100","options_subset":"basic","subset_custom":"","subset_custom_range":"","subset_ot_features_list":"","css_stylesheet":"stylesheet.css","filename_suffix":"-webfont","emsquare":"2048","spacing_adjustment":"0"}
|
@ -0,0 +1,706 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
||||
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script type="text/javascript">
|
||||
(function($) {
|
||||
$.fn.easyTabs = function(option) {
|
||||
var param = jQuery.extend({ fadeSpeed: 'fast', defaultContent: 1, activeClass: 'active' }, option);
|
||||
$(this).each(function() {
|
||||
var thisId = '#' + this.id;
|
||||
if ( param.defaultContent == '' )
|
||||
{
|
||||
param.defaultContent = 1;
|
||||
}
|
||||
if ( typeof param.defaultContent == 'number' )
|
||||
{
|
||||
var defaultTab = $(thisId + ' .tabs li:eq(' + (param.defaultContent - 1) + ') a').attr('href').substr(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
var defaultTab = param.defaultContent;
|
||||
}
|
||||
$(thisId + ' .tabs li a').each(function() {
|
||||
var tabToHide = $(this).attr('href').substr(1);
|
||||
$('#' + tabToHide).addClass('easytabs-tab-content');
|
||||
});
|
||||
hideAll();
|
||||
changeContent(defaultTab);
|
||||
|
||||
function hideAll() {$(thisId + ' .easytabs-tab-content').hide();}
|
||||
|
||||
function changeContent(tabId)
|
||||
{
|
||||
hideAll();
|
||||
$(thisId + ' .tabs li').removeClass(param.activeClass);
|
||||
$(thisId + ' .tabs li a[href=#' + tabId + ']').closest('li').addClass(param.activeClass);
|
||||
if ( param.fadeSpeed != 'none' )
|
||||
{
|
||||
$(thisId + ' #' + tabId).fadeIn(param.fadeSpeed);
|
||||
}
|
||||
else
|
||||
{
|
||||
$(thisId + ' #' + tabId).show();
|
||||
}
|
||||
}
|
||||
|
||||
$(thisId + ' .tabs li').click(function() {
|
||||
var tabId = $(this).find('a').attr('href').substr(1);
|
||||
changeContent(tabId);
|
||||
return false;
|
||||
});
|
||||
});
|
||||
}
|
||||
})(jQuery);
|
||||
</script>
|
||||
<link rel="stylesheet" href="specimen_files/specimen_stylesheet.css" type="text/css" charset="utf-8"/>
|
||||
<link rel="stylesheet" href="stylesheet.css" type="text/css" charset="utf-8"/>
|
||||
|
||||
<style type="text/css">
|
||||
body {
|
||||
font-family: 'questrialregular';
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<title>Questrial Regular Specimen</title>
|
||||
|
||||
|
||||
<script type="text/javascript" charset="utf-8">
|
||||
$(document).ready(function() {
|
||||
$('#container').easyTabs({ defaultContent: 1 });
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="container">
|
||||
<div id="header">
|
||||
Questrial Regular </div>
|
||||
<ul class="tabs">
|
||||
<li><a href="#specimen">Specimen</a></li>
|
||||
<li><a href="#layout">Sample Layout</a></li>
|
||||
<li><a href="#glyphs">Glyphs & Languages</a></li>
|
||||
<li><a href="#installing">Installing Webfonts</a></li>
|
||||
|
||||
</ul>
|
||||
|
||||
<div id="main_content">
|
||||
|
||||
|
||||
<div id="specimen">
|
||||
|
||||
<div class="section">
|
||||
<div class="grid12 firstcol">
|
||||
<div class="huge">AaBb</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<div class="glyph_range">A​B​C​D​E​F​G​H​I​J​K​L​M​N​O​P​Q​R​S​T​U​V​W​X​Y​Z​a​b​c​d​e​f​g​h​i​j​k​l​m​n​o​p​q​r​s​t​u​v​w​x​y​z​1​2​3​4​5​6​7​8​9​0​&​.​,​?​!​@​(​)​#​$​%​*​+​-​=​:​;</div>
|
||||
</div>
|
||||
<div class="section">
|
||||
<div class="grid12 firstcol">
|
||||
<table class="sample_table">
|
||||
<tr>
|
||||
<td>10</td>
|
||||
<td class="size10">abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>11</td>
|
||||
<td class="size11">abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>12</td>
|
||||
<td class="size12">abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>13</td>
|
||||
<td class="size13">abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>14</td>
|
||||
<td class="size14">abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>16</td>
|
||||
<td class="size16">abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>18</td>
|
||||
<td class="size18">abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>20</td>
|
||||
<td class="size20">abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>24</td>
|
||||
<td class="size24">abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>30</td>
|
||||
<td class="size30">abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>36</td>
|
||||
<td class="size36">abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>48</td>
|
||||
<td class="size48">abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>60</td>
|
||||
<td class="size60">abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>72</td>
|
||||
<td class="size72">abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>90</td>
|
||||
<td class="size90">abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="section" id="bodycomparison">
|
||||
|
||||
|
||||
<div id="xheight">
|
||||
<div class="fontbody">◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼body</div>
|
||||
<div class="arialbody">body</div>
|
||||
<div class="verdanabody">body</div>
|
||||
<div class="georgiabody">body</div>
|
||||
</div>
|
||||
<div class="fontbody" style="z-index:1">
|
||||
body<span>Questrial Regular</span>
|
||||
</div>
|
||||
<div class="arialbody" style="z-index:1">
|
||||
body<span>Arial</span>
|
||||
</div>
|
||||
<div class="verdanabody" style="z-index:1">
|
||||
body<span>Verdana</span>
|
||||
</div>
|
||||
<div class="georgiabody" style="z-index:1">
|
||||
body<span>Georgia</span>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="section psample psample_row1" id="">
|
||||
|
||||
<div class="grid2 firstcol">
|
||||
<p class="size10"><span>10.</span>Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.</p>
|
||||
|
||||
</div>
|
||||
<div class="grid3">
|
||||
<p class="size11"><span>11.</span>Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.</p>
|
||||
|
||||
</div>
|
||||
<div class="grid3">
|
||||
<p class="size12"><span>12.</span>Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.</p>
|
||||
|
||||
</div>
|
||||
<div class="grid4">
|
||||
<p class="size13"><span>13.</span>Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.</p>
|
||||
|
||||
</div>
|
||||
<div class="white_blend"></div>
|
||||
|
||||
</div>
|
||||
<div class="section psample psample_row2" id="">
|
||||
<div class="grid3 firstcol">
|
||||
<p class="size14"><span>14.</span>Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.</p>
|
||||
|
||||
</div>
|
||||
<div class="grid4">
|
||||
<p class="size16"><span>16.</span>Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.</p>
|
||||
|
||||
</div>
|
||||
<div class="grid5">
|
||||
<p class="size18"><span>18.</span>Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="white_blend"></div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="section psample psample_row3" id="">
|
||||
<div class="grid5 firstcol">
|
||||
<p class="size20"><span>20.</span>Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.</p>
|
||||
</div>
|
||||
<div class="grid7">
|
||||
<p class="size24"><span>24.</span>Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.</p>
|
||||
</div>
|
||||
|
||||
<div class="white_blend"></div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="section psample psample_row4" id="">
|
||||
<div class="grid12 firstcol">
|
||||
<p class="size30"><span>30.</span>Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.</p>
|
||||
</div>
|
||||
<div class="white_blend"></div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="section psample psample_row1 fullreverse">
|
||||
<div class="grid2 firstcol">
|
||||
<p class="size10"><span>10.</span>Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.</p>
|
||||
|
||||
</div>
|
||||
<div class="grid3">
|
||||
<p class="size11"><span>11.</span>Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.</p>
|
||||
|
||||
</div>
|
||||
<div class="grid3">
|
||||
<p class="size12"><span>12.</span>Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.</p>
|
||||
|
||||
</div>
|
||||
<div class="grid4">
|
||||
<p class="size13"><span>13.</span>Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.</p>
|
||||
|
||||
</div>
|
||||
<div class="black_blend"></div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="section psample psample_row2 fullreverse">
|
||||
<div class="grid3 firstcol">
|
||||
<p class="size14"><span>14.</span>Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.</p>
|
||||
|
||||
</div>
|
||||
<div class="grid4">
|
||||
<p class="size16"><span>16.</span>Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.</p>
|
||||
|
||||
</div>
|
||||
<div class="grid5">
|
||||
<p class="size18"><span>18.</span>Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.</p>
|
||||
|
||||
</div>
|
||||
<div class="black_blend"></div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="section psample fullreverse psample_row3" id="">
|
||||
<div class="grid5 firstcol">
|
||||
<p class="size20"><span>20.</span>Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.</p>
|
||||
</div>
|
||||
<div class="grid7">
|
||||
<p class="size24"><span>24.</span>Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.</p>
|
||||
</div>
|
||||
|
||||
<div class="black_blend"></div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="section psample fullreverse psample_row4" id="" style="border-bottom: 20px #000 solid;">
|
||||
<div class="grid12 firstcol">
|
||||
<p class="size30"><span>30.</span>Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.</p>
|
||||
</div>
|
||||
<div class="black_blend"></div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<div id="layout">
|
||||
|
||||
<div class="section">
|
||||
|
||||
<div class="grid12 firstcol">
|
||||
<h1>Lorem Ipsum Dolor</h1>
|
||||
<h2>Etiam porta sem malesuada magna mollis euismod</h2>
|
||||
|
||||
<p class="byline">By <a href="#link">Aenean Lacinia</a></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section">
|
||||
<div class="grid8 firstcol">
|
||||
<p class="large">Donec sed odio dui. Morbi leo risus, porta ac consectetur ac, vestibulum at eros. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. </p>
|
||||
|
||||
|
||||
<h3>Pellentesque ornare sem</h3>
|
||||
|
||||
<p>Maecenas sed diam eget risus varius blandit sit amet non magna. Maecenas faucibus mollis interdum. Donec ullamcorper nulla non metus auctor fringilla. Nullam id dolor id nibh ultricies vehicula ut id elit. Nullam id dolor id nibh ultricies vehicula ut id elit. </p>
|
||||
|
||||
<p>Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. </p>
|
||||
|
||||
<p>Nulla vitae elit libero, a pharetra augue. Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Aenean lacinia bibendum nulla sed consectetur. </p>
|
||||
|
||||
<p>Nullam quis risus eget urna mollis ornare vel eu leo. Nullam quis risus eget urna mollis ornare vel eu leo. Maecenas sed diam eget risus varius blandit sit amet non magna. Donec ullamcorper nulla non metus auctor fringilla. </p>
|
||||
|
||||
<h3>Cras mattis consectetur</h3>
|
||||
|
||||
<p>Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Aenean lacinia bibendum nulla sed consectetur. Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Cras mattis consectetur purus sit amet fermentum. </p>
|
||||
|
||||
<p>Nullam id dolor id nibh ultricies vehicula ut id elit. Nullam quis risus eget urna mollis ornare vel eu leo. Cras mattis consectetur purus sit amet fermentum.</p>
|
||||
</div>
|
||||
|
||||
<div class="grid4 sidebar">
|
||||
|
||||
<div class="box reverse">
|
||||
<p class="last">Nullam quis risus eget urna mollis ornare vel eu leo. Donec ullamcorper nulla non metus auctor fringilla. Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis. Lorem ipsum dolor sit amet, consectetur adipiscing elit. </p>
|
||||
</div>
|
||||
|
||||
<p class="caption">Maecenas sed diam eget risus varius.</p>
|
||||
|
||||
<p>Vestibulum id ligula porta felis euismod semper. Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Vestibulum id ligula porta felis euismod semper. Sed posuere consectetur est at lobortis. Maecenas sed diam eget risus varius blandit sit amet non magna. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. </p>
|
||||
|
||||
|
||||
<p>Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Aenean lacinia bibendum nulla sed consectetur. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean lacinia bibendum nulla sed consectetur. Nullam quis risus eget urna mollis ornare vel eu leo. </p>
|
||||
|
||||
<p>Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Donec ullamcorper nulla non metus auctor fringilla. Maecenas faucibus mollis interdum. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. </p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<div id="glyphs">
|
||||
<div class="section">
|
||||
<div class="grid12 firstcol">
|
||||
|
||||
<h1>Language Support</h1>
|
||||
<p>The subset of Questrial Regular in this kit supports the following languages:<br/>
|
||||
|
||||
Albanian, Basque, Breton, Chamorro, Danish, Dutch, English, Faroese, Finnish, French, Frisian, Galician, German, Icelandic, Italian, Malagasy, Norwegian, Portuguese, Spanish, Alsatian, Aragonese, Arapaho, Arrernte, Asturian, Aymara, Bislama, Cebuano, Corsican, Fijian, French_creole, Genoese, Gilbertese, Greenlandic, Haitian_creole, Hiligaynon, Hmong, Hopi, Ibanag, Iloko_ilokano, Indonesian, Interglossa_glosa, Interlingua, Irish_gaelic, Jerriais, Lojban, Lombard, Luxembourgeois, Manx, Mohawk, Norfolk_pitcairnese, Occitan, Oromo, Pangasinan, Papiamento, Piedmontese, Potawatomi, Rhaeto-romance, Romansh, Rotokas, Sami_lule, Samoan, Sardinian, Scots_gaelic, Seychelles_creole, Shona, Sicilian, Somali, Southern_ndebele, Swahili, Swati_swazi, Tagalog_filipino_pilipino, Tetum, Tok_pisin, Uyghur_latinized, Volapuk, Walloon, Warlpiri, Xhosa, Yapese, Zulu, Latinbasic, Ubasic, Demo </p>
|
||||
<h1>Glyph Chart</h1>
|
||||
<p>The subset of Questrial Regular in this kit includes all the glyphs listed below. Unicode entities are included above each glyph to help you insert individual characters into your layout.</p>
|
||||
<div id="glyph_chart">
|
||||
|
||||
<div><p>&#13;</p> </div>
|
||||
<div><p>&#32;</p> </div>
|
||||
<div><p>&#33;</p>!</div>
|
||||
<div><p>&#34;</p>"</div>
|
||||
<div><p>&#35;</p>#</div>
|
||||
<div><p>&#36;</p>$</div>
|
||||
<div><p>&#37;</p>%</div>
|
||||
<div><p>&#38;</p>&</div>
|
||||
<div><p>&#39;</p>'</div>
|
||||
<div><p>&#40;</p>(</div>
|
||||
<div><p>&#41;</p>)</div>
|
||||
<div><p>&#42;</p>*</div>
|
||||
<div><p>&#43;</p>+</div>
|
||||
<div><p>&#44;</p>,</div>
|
||||
<div><p>&#45;</p>-</div>
|
||||
<div><p>&#46;</p>.</div>
|
||||
<div><p>&#47;</p>/</div>
|
||||
<div><p>&#48;</p>0</div>
|
||||
<div><p>&#49;</p>1</div>
|
||||
<div><p>&#50;</p>2</div>
|
||||
<div><p>&#51;</p>3</div>
|
||||
<div><p>&#52;</p>4</div>
|
||||
<div><p>&#53;</p>5</div>
|
||||
<div><p>&#54;</p>6</div>
|
||||
<div><p>&#55;</p>7</div>
|
||||
<div><p>&#56;</p>8</div>
|
||||
<div><p>&#57;</p>9</div>
|
||||
<div><p>&#58;</p>:</div>
|
||||
<div><p>&#59;</p>;</div>
|
||||
<div><p>&#60;</p><</div>
|
||||
<div><p>&#61;</p>=</div>
|
||||
<div><p>&#62;</p>></div>
|
||||
<div><p>&#63;</p>?</div>
|
||||
<div><p>&#64;</p>@</div>
|
||||
<div><p>&#65;</p>A</div>
|
||||
<div><p>&#66;</p>B</div>
|
||||
<div><p>&#67;</p>C</div>
|
||||
<div><p>&#68;</p>D</div>
|
||||
<div><p>&#69;</p>E</div>
|
||||
<div><p>&#70;</p>F</div>
|
||||
<div><p>&#71;</p>G</div>
|
||||
<div><p>&#72;</p>H</div>
|
||||
<div><p>&#73;</p>I</div>
|
||||
<div><p>&#74;</p>J</div>
|
||||
<div><p>&#75;</p>K</div>
|
||||
<div><p>&#76;</p>L</div>
|
||||
<div><p>&#77;</p>M</div>
|
||||
<div><p>&#78;</p>N</div>
|
||||
<div><p>&#79;</p>O</div>
|
||||
<div><p>&#80;</p>P</div>
|
||||
<div><p>&#81;</p>Q</div>
|
||||
<div><p>&#82;</p>R</div>
|
||||
<div><p>&#83;</p>S</div>
|
||||
<div><p>&#84;</p>T</div>
|
||||
<div><p>&#85;</p>U</div>
|
||||
<div><p>&#86;</p>V</div>
|
||||
<div><p>&#87;</p>W</div>
|
||||
<div><p>&#88;</p>X</div>
|
||||
<div><p>&#89;</p>Y</div>
|
||||
<div><p>&#90;</p>Z</div>
|
||||
<div><p>&#91;</p>[</div>
|
||||
<div><p>&#92;</p>\</div>
|
||||
<div><p>&#93;</p>]</div>
|
||||
<div><p>&#94;</p>^</div>
|
||||
<div><p>&#95;</p>_</div>
|
||||
<div><p>&#96;</p>`</div>
|
||||
<div><p>&#97;</p>a</div>
|
||||
<div><p>&#98;</p>b</div>
|
||||
<div><p>&#99;</p>c</div>
|
||||
<div><p>&#100;</p>d</div>
|
||||
<div><p>&#101;</p>e</div>
|
||||
<div><p>&#102;</p>f</div>
|
||||
<div><p>&#103;</p>g</div>
|
||||
<div><p>&#104;</p>h</div>
|
||||
<div><p>&#105;</p>i</div>
|
||||
<div><p>&#106;</p>j</div>
|
||||
<div><p>&#107;</p>k</div>
|
||||
<div><p>&#108;</p>l</div>
|
||||
<div><p>&#109;</p>m</div>
|
||||
<div><p>&#110;</p>n</div>
|
||||
<div><p>&#111;</p>o</div>
|
||||
<div><p>&#112;</p>p</div>
|
||||
<div><p>&#113;</p>q</div>
|
||||
<div><p>&#114;</p>r</div>
|
||||
<div><p>&#115;</p>s</div>
|
||||
<div><p>&#116;</p>t</div>
|
||||
<div><p>&#117;</p>u</div>
|
||||
<div><p>&#118;</p>v</div>
|
||||
<div><p>&#119;</p>w</div>
|
||||
<div><p>&#120;</p>x</div>
|
||||
<div><p>&#121;</p>y</div>
|
||||
<div><p>&#122;</p>z</div>
|
||||
<div><p>&#123;</p>{</div>
|
||||
<div><p>&#124;</p>|</div>
|
||||
<div><p>&#125;</p>}</div>
|
||||
<div><p>&#126;</p>~</div>
|
||||
<div><p>&#160;</p> </div>
|
||||
<div><p>&#161;</p>¡</div>
|
||||
<div><p>&#162;</p>¢</div>
|
||||
<div><p>&#163;</p>£</div>
|
||||
<div><p>&#164;</p>¤</div>
|
||||
<div><p>&#165;</p>¥</div>
|
||||
<div><p>&#166;</p>¦</div>
|
||||
<div><p>&#167;</p>§</div>
|
||||
<div><p>&#168;</p>¨</div>
|
||||
<div><p>&#169;</p>©</div>
|
||||
<div><p>&#170;</p>ª</div>
|
||||
<div><p>&#171;</p>«</div>
|
||||
<div><p>&#172;</p>¬</div>
|
||||
<div><p>&#173;</p>­</div>
|
||||
<div><p>&#174;</p>®</div>
|
||||
<div><p>&#175;</p>¯</div>
|
||||
<div><p>&#176;</p>°</div>
|
||||
<div><p>&#177;</p>±</div>
|
||||
<div><p>&#178;</p>²</div>
|
||||
<div><p>&#179;</p>³</div>
|
||||
<div><p>&#180;</p>´</div>
|
||||
<div><p>&#181;</p>µ</div>
|
||||
<div><p>&#182;</p>¶</div>
|
||||
<div><p>&#183;</p>·</div>
|
||||
<div><p>&#184;</p>¸</div>
|
||||
<div><p>&#185;</p>¹</div>
|
||||
<div><p>&#186;</p>º</div>
|
||||
<div><p>&#187;</p>»</div>
|
||||
<div><p>&#188;</p>¼</div>
|
||||
<div><p>&#189;</p>½</div>
|
||||
<div><p>&#190;</p>¾</div>
|
||||
<div><p>&#191;</p>¿</div>
|
||||
<div><p>&#192;</p>À</div>
|
||||
<div><p>&#193;</p>Á</div>
|
||||
<div><p>&#194;</p>Â</div>
|
||||
<div><p>&#195;</p>Ã</div>
|
||||
<div><p>&#196;</p>Ä</div>
|
||||
<div><p>&#197;</p>Å</div>
|
||||
<div><p>&#198;</p>Æ</div>
|
||||
<div><p>&#199;</p>Ç</div>
|
||||
<div><p>&#200;</p>È</div>
|
||||
<div><p>&#201;</p>É</div>
|
||||
<div><p>&#202;</p>Ê</div>
|
||||
<div><p>&#203;</p>Ë</div>
|
||||
<div><p>&#204;</p>Ì</div>
|
||||
<div><p>&#205;</p>Í</div>
|
||||
<div><p>&#206;</p>Î</div>
|
||||
<div><p>&#207;</p>Ï</div>
|
||||
<div><p>&#208;</p>Ð</div>
|
||||
<div><p>&#209;</p>Ñ</div>
|
||||
<div><p>&#210;</p>Ò</div>
|
||||
<div><p>&#211;</p>Ó</div>
|
||||
<div><p>&#212;</p>Ô</div>
|
||||
<div><p>&#213;</p>Õ</div>
|
||||
<div><p>&#214;</p>Ö</div>
|
||||
<div><p>&#215;</p>×</div>
|
||||
<div><p>&#216;</p>Ø</div>
|
||||
<div><p>&#217;</p>Ù</div>
|
||||
<div><p>&#218;</p>Ú</div>
|
||||
<div><p>&#219;</p>Û</div>
|
||||
<div><p>&#220;</p>Ü</div>
|
||||
<div><p>&#221;</p>Ý</div>
|
||||
<div><p>&#222;</p>Þ</div>
|
||||
<div><p>&#223;</p>ß</div>
|
||||
<div><p>&#224;</p>à</div>
|
||||
<div><p>&#225;</p>á</div>
|
||||
<div><p>&#226;</p>â</div>
|
||||
<div><p>&#227;</p>ã</div>
|
||||
<div><p>&#228;</p>ä</div>
|
||||
<div><p>&#229;</p>å</div>
|
||||
<div><p>&#230;</p>æ</div>
|
||||
<div><p>&#231;</p>ç</div>
|
||||
<div><p>&#232;</p>è</div>
|
||||
<div><p>&#233;</p>é</div>
|
||||
<div><p>&#234;</p>ê</div>
|
||||
<div><p>&#235;</p>ë</div>
|
||||
<div><p>&#236;</p>ì</div>
|
||||
<div><p>&#237;</p>í</div>
|
||||
<div><p>&#238;</p>î</div>
|
||||
<div><p>&#239;</p>ï</div>
|
||||
<div><p>&#240;</p>ð</div>
|
||||
<div><p>&#241;</p>ñ</div>
|
||||
<div><p>&#242;</p>ò</div>
|
||||
<div><p>&#243;</p>ó</div>
|
||||
<div><p>&#244;</p>ô</div>
|
||||
<div><p>&#245;</p>õ</div>
|
||||
<div><p>&#246;</p>ö</div>
|
||||
<div><p>&#247;</p>÷</div>
|
||||
<div><p>&#248;</p>ø</div>
|
||||
<div><p>&#249;</p>ù</div>
|
||||
<div><p>&#250;</p>ú</div>
|
||||
<div><p>&#251;</p>û</div>
|
||||
<div><p>&#252;</p>ü</div>
|
||||
<div><p>&#253;</p>ý</div>
|
||||
<div><p>&#254;</p>þ</div>
|
||||
<div><p>&#255;</p>ÿ</div>
|
||||
<div><p>&#338;</p>Œ</div>
|
||||
<div><p>&#339;</p>œ</div>
|
||||
<div><p>&#376;</p>Ÿ</div>
|
||||
<div><p>&#710;</p>ˆ</div>
|
||||
<div><p>&#732;</p>˜</div>
|
||||
<div><p>&#8192;</p> </div>
|
||||
<div><p>&#8193;</p> </div>
|
||||
<div><p>&#8194;</p> </div>
|
||||
<div><p>&#8195;</p> </div>
|
||||
<div><p>&#8196;</p> </div>
|
||||
<div><p>&#8197;</p> </div>
|
||||
<div><p>&#8198;</p> </div>
|
||||
<div><p>&#8199;</p> </div>
|
||||
<div><p>&#8200;</p> </div>
|
||||
<div><p>&#8201;</p> </div>
|
||||
<div><p>&#8202;</p> </div>
|
||||
<div><p>&#8208;</p>‐</div>
|
||||
<div><p>&#8209;</p>‑</div>
|
||||
<div><p>&#8210;</p>‒</div>
|
||||
<div><p>&#8211;</p>–</div>
|
||||
<div><p>&#8212;</p>—</div>
|
||||
<div><p>&#8216;</p>‘</div>
|
||||
<div><p>&#8217;</p>’</div>
|
||||
<div><p>&#8218;</p>‚</div>
|
||||
<div><p>&#8220;</p>“</div>
|
||||
<div><p>&#8221;</p>”</div>
|
||||
<div><p>&#8222;</p>„</div>
|
||||
<div><p>&#8226;</p>•</div>
|
||||
<div><p>&#8230;</p>…</div>
|
||||
<div><p>&#8239;</p> </div>
|
||||
<div><p>&#8249;</p>‹</div>
|
||||
<div><p>&#8250;</p>›</div>
|
||||
<div><p>&#8287;</p> </div>
|
||||
<div><p>&#8364;</p>€</div>
|
||||
<div><p>&#8482;</p>™</div>
|
||||
<div><p>&#9724;</p>◼</div>
|
||||
<div><p>&#64257;</p>fi</div>
|
||||
<div><p>&#64258;</p>fl</div>
|
||||
<div><p>&#64259;</p>ffi</div>
|
||||
<div><p>&#64260;</p>ffl</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div id="specs">
|
||||
|
||||
</div>
|
||||
|
||||
<div id="installing">
|
||||
<div class="section">
|
||||
<div class="grid7 firstcol">
|
||||
<h1>Installing Webfonts</h1>
|
||||
|
||||
<p>Webfonts are supported by all major browser platforms but not all in the same way. There are currently four different font formats that must be included in order to target all browsers. This includes TTF, WOFF, EOT and SVG.</p>
|
||||
|
||||
<h2>1. Upload your webfonts</h2>
|
||||
<p>You must upload your webfont kit to your website. They should be in or near the same directory as your CSS files.</p>
|
||||
|
||||
<h2>2. Include the webfont stylesheet</h2>
|
||||
<p>A special CSS @font-face declaration helps the various browsers select the appropriate font it needs without causing you a bunch of headaches. Learn more about this syntax by reading the <a href="https://www.fontspring.com/blog/further-hardening-of-the-bulletproof-syntax">Fontspring blog post</a> about it. The code for it is as follows:</p>
|
||||
|
||||
|
||||
<code>
|
||||
@font-face{
|
||||
font-family: 'MyWebFont';
|
||||
src: url('WebFont.eot');
|
||||
src: url('WebFont.eot?#iefix') format('embedded-opentype'),
|
||||
url('WebFont.woff') format('woff'),
|
||||
url('WebFont.ttf') format('truetype'),
|
||||
url('WebFont.svg#webfont') format('svg');
|
||||
}
|
||||
</code>
|
||||
|
||||
<p>We've already gone ahead and generated the code for you. All you have to do is link to the stylesheet in your HTML, like this:</p>
|
||||
<code><link rel="stylesheet" href="stylesheet.css" type="text/css" charset="utf-8" /></code>
|
||||
|
||||
<h2>3. Modify your own stylesheet</h2>
|
||||
<p>To take advantage of your new fonts, you must tell your stylesheet to use them. Look at the original @font-face declaration above and find the property called "font-family." The name linked there will be what you use to reference the font. Prepend that webfont name to the font stack in the "font-family" property, inside the selector you want to change. For example:</p>
|
||||
<code>p { font-family: 'WebFont', Arial, sans-serif; }</code>
|
||||
|
||||
<h2>4. Test</h2>
|
||||
<p>Getting webfonts to work cross-browser <em>can</em> be tricky. Use the information in the sidebar to help you if you find that fonts aren't loading in a particular browser.</p>
|
||||
</div>
|
||||
|
||||
<div class="grid5 sidebar">
|
||||
<div class="box">
|
||||
<h2>Troubleshooting<br/>Font-Face Problems</h2>
|
||||
<p>Having trouble getting your webfonts to load in your new website? Here are some tips to sort out what might be the problem.</p>
|
||||
|
||||
<h3>Fonts not showing in any browser</h3>
|
||||
|
||||
<p>This sounds like you need to work on the plumbing. You either did not upload the fonts to the correct directory, or you did not link the fonts properly in the CSS. If you've confirmed that all this is correct and you still have a problem, take a look at your .htaccess file and see if requests are getting intercepted.</p>
|
||||
|
||||
<h3>Fonts not loading in iPhone or iPad</h3>
|
||||
|
||||
<p>The most common problem here is that you are serving the fonts from an IIS server. IIS refuses to serve files that have unknown MIME types. If that is the case, you must set the MIME type for SVG to "image/svg+xml" in the server settings. Follow these instructions from Microsoft if you need help.</p>
|
||||
|
||||
<h3>Fonts not loading in Firefox</h3>
|
||||
|
||||
<p>The primary reason for this failure? You are still using a version Firefox older than 3.5. So upgrade already! If that isn't it, then you are very likely serving fonts from a different domain. Firefox requires that all font assets be served from the same domain. Lastly it is possible that you need to add WOFF to your list of MIME types (if you are serving via IIS.)</p>
|
||||
|
||||
<h3>Fonts not loading in IE</h3>
|
||||
|
||||
<p>Are you looking at Internet Explorer on an actual Windows machine or are you cheating by using a service like Adobe BrowserLab? Many of these screenshot services do not render @font-face for IE. Best to test it on a real machine.</p>
|
||||
|
||||
<h3>Fonts not loading in IE9</h3>
|
||||
|
||||
<p>IE9, like Firefox, requires that fonts be served from the same domain as the website. Make sure that is the case.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div id="footer">
|
||||
<p>©2010-2017 Font Squirrel. All rights reserved.</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,370 @@
|
||||
/*Notes about grid:
|
||||
Columns: 12
|
||||
Grid Width: 825px
|
||||
Column Width: 55px
|
||||
Gutter Width: 15px
|
||||
-------------------------------*/
|
||||
|
||||
|
||||
.section {
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
|
||||
.section:after {
|
||||
content: '.';
|
||||
display: block;
|
||||
height: 0;
|
||||
clear: both;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.section {
|
||||
*zoom: 1;
|
||||
}
|
||||
|
||||
.section .firstcolumn,
|
||||
.section .firstcol {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
|
||||
/* Border on left hand side of a column. */
|
||||
.border {
|
||||
padding-left: 7px;
|
||||
margin-left: 7px;
|
||||
border-left: 1px solid #eee;
|
||||
}
|
||||
|
||||
/* Border with more whitespace, spans one column. */
|
||||
.colborder {
|
||||
padding-left: 42px;
|
||||
margin-left: 42px;
|
||||
border-left: 1px solid #eee;
|
||||
}
|
||||
|
||||
|
||||
/* The Grid Classes */
|
||||
.grid1, .grid1_2cols, .grid1_3cols, .grid1_4cols, .grid2, .grid2_3cols, .grid2_4cols, .grid3, .grid3_2cols, .grid3_4cols, .grid4, .grid4_3cols, .grid5, .grid5_2cols, .grid5_3cols, .grid5_4cols, .grid6, .grid6_4cols, .grid7, .grid7_2cols, .grid7_3cols, .grid7_4cols, .grid8, .grid8_3cols, .grid9, .grid9_2cols, .grid9_4cols, .grid10, .grid10_3cols, .grid10_4cols, .grid11, .grid11_2cols, .grid11_3cols, .grid11_4cols, .grid12 {
|
||||
margin-left: 15px;
|
||||
float: left;
|
||||
display: inline;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
|
||||
.width1, .grid1, .span-1 {
|
||||
width: 55px;
|
||||
}
|
||||
|
||||
.width1_2cols, .grid1_2cols {
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
.width1_3cols, .grid1_3cols {
|
||||
width: 8px;
|
||||
}
|
||||
|
||||
.width1_4cols, .grid1_4cols {
|
||||
width: 2px;
|
||||
}
|
||||
|
||||
.input_width1 {
|
||||
width: 49px;
|
||||
}
|
||||
|
||||
.width2, .grid2, .span-2 {
|
||||
width: 125px;
|
||||
}
|
||||
|
||||
.width2_3cols, .grid2_3cols {
|
||||
width: 31px;
|
||||
}
|
||||
|
||||
.width2_4cols, .grid2_4cols {
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
.input_width2 {
|
||||
width: 119px;
|
||||
}
|
||||
|
||||
.width3, .grid3, .span-3 {
|
||||
width: 195px;
|
||||
}
|
||||
|
||||
.width3_2cols, .grid3_2cols {
|
||||
width: 90px;
|
||||
}
|
||||
|
||||
.width3_4cols, .grid3_4cols {
|
||||
width: 37px;
|
||||
}
|
||||
|
||||
.input_width3 {
|
||||
width: 189px;
|
||||
}
|
||||
|
||||
.width4, .grid4, .span-4 {
|
||||
width: 265px;
|
||||
}
|
||||
|
||||
.width4_3cols, .grid4_3cols {
|
||||
width: 78px;
|
||||
}
|
||||
|
||||
.input_width4 {
|
||||
width: 259px;
|
||||
}
|
||||
|
||||
.width5, .grid5, .span-5 {
|
||||
width: 335px;
|
||||
}
|
||||
|
||||
.width5_2cols, .grid5_2cols {
|
||||
width: 160px;
|
||||
}
|
||||
|
||||
.width5_3cols, .grid5_3cols {
|
||||
width: 101px;
|
||||
}
|
||||
|
||||
.width5_4cols, .grid5_4cols {
|
||||
width: 72px;
|
||||
}
|
||||
|
||||
.input_width5 {
|
||||
width: 329px;
|
||||
}
|
||||
|
||||
.width6, .grid6, .span-6 {
|
||||
width: 405px;
|
||||
}
|
||||
|
||||
.width6_4cols, .grid6_4cols {
|
||||
width: 90px;
|
||||
}
|
||||
|
||||
.input_width6 {
|
||||
width: 399px;
|
||||
}
|
||||
|
||||
.width7, .grid7, .span-7 {
|
||||
width: 475px;
|
||||
}
|
||||
|
||||
.width7_2cols, .grid7_2cols {
|
||||
width: 230px;
|
||||
}
|
||||
|
||||
.width7_3cols, .grid7_3cols {
|
||||
width: 148px;
|
||||
}
|
||||
|
||||
.width7_4cols, .grid7_4cols {
|
||||
width: 107px;
|
||||
}
|
||||
|
||||
.input_width7 {
|
||||
width: 469px;
|
||||
}
|
||||
|
||||
.width8, .grid8, .span-8 {
|
||||
width: 545px;
|
||||
}
|
||||
|
||||
.width8_3cols, .grid8_3cols {
|
||||
width: 171px;
|
||||
}
|
||||
|
||||
.input_width8 {
|
||||
width: 539px;
|
||||
}
|
||||
|
||||
.width9, .grid9, .span-9 {
|
||||
width: 615px;
|
||||
}
|
||||
|
||||
.width9_2cols, .grid9_2cols {
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
.width9_4cols, .grid9_4cols {
|
||||
width: 142px;
|
||||
}
|
||||
|
||||
.input_width9 {
|
||||
width: 609px;
|
||||
}
|
||||
|
||||
.width10, .grid10, .span-10 {
|
||||
width: 685px;
|
||||
}
|
||||
|
||||
.width10_3cols, .grid10_3cols {
|
||||
width: 218px;
|
||||
}
|
||||
|
||||
.width10_4cols, .grid10_4cols {
|
||||
width: 160px;
|
||||
}
|
||||
|
||||
.input_width10 {
|
||||
width: 679px;
|
||||
}
|
||||
|
||||
.width11, .grid11, .span-11 {
|
||||
width: 755px;
|
||||
}
|
||||
|
||||
.width11_2cols, .grid11_2cols {
|
||||
width: 370px;
|
||||
}
|
||||
|
||||
.width11_3cols, .grid11_3cols {
|
||||
width: 241px;
|
||||
}
|
||||
|
||||
.width11_4cols, .grid11_4cols {
|
||||
width: 177px;
|
||||
}
|
||||
|
||||
.input_width11 {
|
||||
width: 749px;
|
||||
}
|
||||
|
||||
.width12, .grid12, .span-12 {
|
||||
width: 825px;
|
||||
}
|
||||
|
||||
.input_width12 {
|
||||
width: 819px;
|
||||
}
|
||||
|
||||
/* Subdivided grid spaces */
|
||||
.emptycols_left1, .prepend-1 {
|
||||
padding-left: 70px;
|
||||
}
|
||||
|
||||
.emptycols_right1, .append-1 {
|
||||
padding-right: 70px;
|
||||
}
|
||||
|
||||
.emptycols_left2, .prepend-2 {
|
||||
padding-left: 140px;
|
||||
}
|
||||
|
||||
.emptycols_right2, .append-2 {
|
||||
padding-right: 140px;
|
||||
}
|
||||
|
||||
.emptycols_left3, .prepend-3 {
|
||||
padding-left: 210px;
|
||||
}
|
||||
|
||||
.emptycols_right3, .append-3 {
|
||||
padding-right: 210px;
|
||||
}
|
||||
|
||||
.emptycols_left4, .prepend-4 {
|
||||
padding-left: 280px;
|
||||
}
|
||||
|
||||
.emptycols_right4, .append-4 {
|
||||
padding-right: 280px;
|
||||
}
|
||||
|
||||
.emptycols_left5, .prepend-5 {
|
||||
padding-left: 350px;
|
||||
}
|
||||
|
||||
.emptycols_right5, .append-5 {
|
||||
padding-right: 350px;
|
||||
}
|
||||
|
||||
.emptycols_left6, .prepend-6 {
|
||||
padding-left: 420px;
|
||||
}
|
||||
|
||||
.emptycols_right6, .append-6 {
|
||||
padding-right: 420px;
|
||||
}
|
||||
|
||||
.emptycols_left7, .prepend-7 {
|
||||
padding-left: 490px;
|
||||
}
|
||||
|
||||
.emptycols_right7, .append-7 {
|
||||
padding-right: 490px;
|
||||
}
|
||||
|
||||
.emptycols_left8, .prepend-8 {
|
||||
padding-left: 560px;
|
||||
}
|
||||
|
||||
.emptycols_right8, .append-8 {
|
||||
padding-right: 560px;
|
||||
}
|
||||
|
||||
.emptycols_left9, .prepend-9 {
|
||||
padding-left: 630px;
|
||||
}
|
||||
|
||||
.emptycols_right9, .append-9 {
|
||||
padding-right: 630px;
|
||||
}
|
||||
|
||||
.emptycols_left10, .prepend-10 {
|
||||
padding-left: 700px;
|
||||
}
|
||||
|
||||
.emptycols_right10, .append-10 {
|
||||
padding-right: 700px;
|
||||
}
|
||||
|
||||
.emptycols_left11, .prepend-11 {
|
||||
padding-left: 770px;
|
||||
}
|
||||
|
||||
.emptycols_right11, .append-11 {
|
||||
padding-right: 770px;
|
||||
}
|
||||
|
||||
.pull-1 {
|
||||
margin-left: -70px;
|
||||
}
|
||||
|
||||
.push-1 {
|
||||
margin-right: -70px;
|
||||
margin-left: 18px;
|
||||
float: right;
|
||||
}
|
||||
|
||||
.pull-2 {
|
||||
margin-left: -140px;
|
||||
}
|
||||
|
||||
.push-2 {
|
||||
margin-right: -140px;
|
||||
margin-left: 18px;
|
||||
float: right;
|
||||
}
|
||||
|
||||
.pull-3 {
|
||||
margin-left: -210px;
|
||||
}
|
||||
|
||||
.push-3 {
|
||||
margin-right: -210px;
|
||||
margin-left: 18px;
|
||||
float: right;
|
||||
}
|
||||
|
||||
.pull-4 {
|
||||
margin-left: -280px;
|
||||
}
|
||||
|
||||
.push-4 {
|
||||
margin-right: -280px;
|
||||
margin-left: 18px;
|
||||
float: right;
|
||||
}
|
@ -0,0 +1,502 @@
|
||||
@import url('grid_12-825-55-15.css');
|
||||
|
||||
/*
|
||||
CSS Reset by Eric Meyer - Released under Public Domain
|
||||
http://meyerweb.com/eric/tools/css/reset/
|
||||
*/
|
||||
html, body, div, span, applet, object, iframe,
|
||||
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
|
||||
a, abbr, acronym, address, big, cite, code,
|
||||
del, dfn, em, font, img, ins, kbd, q, s, samp,
|
||||
small, strike, strong, sub, sup, tt, var,
|
||||
b, u, i, center, dl, dt, dd, ol, ul, li,
|
||||
fieldset, form, label, legend, table,
|
||||
caption, tbody, tfoot, thead, tr, th, td {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
outline: 0;
|
||||
font-size: 100%;
|
||||
vertical-align: baseline;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
body {
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
ol, ul {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
blockquote, q {
|
||||
quotes: none;
|
||||
}
|
||||
|
||||
blockquote:before, blockquote:after,
|
||||
q:before, q:after {
|
||||
content: '';
|
||||
content: none;
|
||||
}
|
||||
|
||||
:focus {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
ins {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
del {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
}
|
||||
|
||||
|
||||
body {
|
||||
color: #000;
|
||||
background-color: #dcdcdc;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: #1883ba;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 32px;
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
#container {
|
||||
width: 865px;
|
||||
margin: 0px auto;
|
||||
}
|
||||
|
||||
|
||||
#header {
|
||||
padding: 20px;
|
||||
font-size: 36px;
|
||||
background-color: #000;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
#header span {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
#main_content {
|
||||
background-color: #fff;
|
||||
padding: 60px 20px 20px;
|
||||
}
|
||||
|
||||
|
||||
#footer p {
|
||||
margin: 0;
|
||||
padding-top: 10px;
|
||||
padding-bottom: 50px;
|
||||
color: #333;
|
||||
font: 10px Arial, sans-serif;
|
||||
}
|
||||
|
||||
.tabs {
|
||||
width: 100%;
|
||||
height: 31px;
|
||||
background-color: #444;
|
||||
}
|
||||
|
||||
.tabs li {
|
||||
float: left;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
background-color: #444;
|
||||
}
|
||||
|
||||
.tabs li a {
|
||||
display: block;
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
font: bold 11px/11px 'Arial';
|
||||
text-transform: uppercase;
|
||||
padding: 10px 15px;
|
||||
border-right: 1px solid #fff;
|
||||
}
|
||||
|
||||
.tabs li a:hover {
|
||||
background-color: #00b3ff;
|
||||
|
||||
}
|
||||
|
||||
.tabs li.active a {
|
||||
color: #000;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
|
||||
div.huge {
|
||||
|
||||
font-size: 300px;
|
||||
line-height: 1em;
|
||||
padding: 0;
|
||||
letter-spacing: -.02em;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
div.glyph_range {
|
||||
font-size: 72px;
|
||||
line-height: 1.1em;
|
||||
}
|
||||
|
||||
.size10 {
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.size11 {
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.size12 {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.size13 {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.size14 {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.size16 {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.size18 {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.size20 {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.size24 {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.size30 {
|
||||
font-size: 30px;
|
||||
}
|
||||
|
||||
.size36 {
|
||||
font-size: 36px;
|
||||
}
|
||||
|
||||
.size48 {
|
||||
font-size: 48px;
|
||||
}
|
||||
|
||||
.size60 {
|
||||
font-size: 60px;
|
||||
}
|
||||
|
||||
.size72 {
|
||||
font-size: 72px;
|
||||
}
|
||||
|
||||
.size90 {
|
||||
font-size: 90px;
|
||||
}
|
||||
|
||||
|
||||
.psample_row1 {
|
||||
height: 120px;
|
||||
}
|
||||
|
||||
.psample_row1 {
|
||||
height: 120px;
|
||||
}
|
||||
|
||||
.psample_row2 {
|
||||
height: 160px;
|
||||
}
|
||||
|
||||
.psample_row3 {
|
||||
height: 160px;
|
||||
}
|
||||
|
||||
.psample_row4 {
|
||||
height: 160px;
|
||||
}
|
||||
|
||||
.psample {
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.psample p {
|
||||
line-height: 1.3em;
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.psample span {
|
||||
margin-right: .5em;
|
||||
}
|
||||
|
||||
.white_blend {
|
||||
width: 100%;
|
||||
height: 61px;
|
||||
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAVkAAAA9CAYAAAAH4BojAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAO1JREFUeNrs3TsKgFAMRUE/eer+NxztxMYuEWQG3ECKwwUF58ycAKixOAGAyAKILAAiCyCyACILgMgCiCyAyAIgsgAiCyCyAIgsgMgCiCwAIgsgsgAiC4DIAogsACIL0CWuZ3UGgLrIhjMA1EV2OAOAJQtgyQLwjOzmDAAiCyCyAIgsQFtkd2cAEFkAkQVAZAHaIns4A4AlC2DJAiCyACILILIAiCzAV5H1dQGAJQsgsgCILIDIAvwisl58AViyAJYsACILILIAIgvAe2T9EhxAZAFEFgCRBeiL7HAGgLrIhjMAWLIAliwAt1OAAQDwygTBulLIlQAAAABJRU5ErkJggg==);
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.black_blend {
|
||||
width: 100%;
|
||||
height: 61px;
|
||||
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAVkAAAA9CAYAAAAH4BojAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAPJJREFUeNrs3TEKhTAQRVGjibr/9QoxhY2N3Ywo50A28IrLwP9g6b1PAMSYTQAgsgAiC4DIAogsgMgCILIAIgsgsgCILIDIAogsACILILIAIguAyAKILIDIAiCyACILgMgCZCnjLWYAiFGvB0BQZJsZAFyyAC5ZAO6RXc0AILIAIguAyAKkRXYzA4DIAogsACILkBbZ3QwALlkAlywAIgsgsgAiC4DIArwVWf8uAHDJAogsACILILIAv4isH74AXLIALlkARBZAZAFEFoDnyPokOIDIAogsACILkBfZZgaAuMhWMwC4ZAE+p4x3mAEgxinAAJ+XBbPWGkwAAAAAAElFTkSuQmCC);
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.fullreverse {
|
||||
background: #000 !important;
|
||||
color: #fff !important;
|
||||
margin-left: -20px;
|
||||
padding-left: 20px;
|
||||
margin-right: -20px;
|
||||
padding-right: 20px;
|
||||
padding: 20px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
|
||||
.sample_table td {
|
||||
padding-top: 3px;
|
||||
padding-bottom: 5px;
|
||||
padding-left: 5px;
|
||||
vertical-align: middle;
|
||||
line-height: 1.2em;
|
||||
}
|
||||
|
||||
.sample_table td:first-child {
|
||||
background-color: #eee;
|
||||
text-align: right;
|
||||
padding-right: 5px;
|
||||
padding-left: 0;
|
||||
padding: 5px;
|
||||
font: 11px/12px 'Courier New', Courier, mono;
|
||||
}
|
||||
|
||||
code {
|
||||
white-space: pre;
|
||||
background-color: #eee;
|
||||
display: block;
|
||||
padding: 10px;
|
||||
margin-bottom: 18px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
|
||||
.bottom, .last {
|
||||
margin-bottom: 0 !important;
|
||||
padding-bottom: 0 !important;
|
||||
}
|
||||
|
||||
.box {
|
||||
padding: 18px;
|
||||
margin-bottom: 18px;
|
||||
background: #eee;
|
||||
}
|
||||
|
||||
.reverse, .reversed {
|
||||
background: #000 !important;
|
||||
color: #fff !important;
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
#bodycomparison {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
font-size: 72px;
|
||||
height: 90px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
#bodycomparison div {
|
||||
font-size: 72px;
|
||||
line-height: 90px;
|
||||
display: inline;
|
||||
margin: 0 15px 0 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#bodycomparison div span {
|
||||
font: 10px Arial;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
#xheight {
|
||||
float: none;
|
||||
position: absolute;
|
||||
color: #d9f3ff;
|
||||
font-size: 72px;
|
||||
line-height: 90px;
|
||||
}
|
||||
|
||||
.fontbody {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.arialbody {
|
||||
font-family: Arial;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.verdanabody {
|
||||
font-family: Verdana;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.georgiabody {
|
||||
font-family: Georgia;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* @group Layout page
|
||||
*/
|
||||
|
||||
#layout h1 {
|
||||
font-size: 36px;
|
||||
line-height: 42px;
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
#layout h2 {
|
||||
font-size: 24px;
|
||||
line-height: 23px;
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
#layout h3 {
|
||||
font-size: 22px;
|
||||
line-height: 1.4em;
|
||||
margin-top: 1em;
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
|
||||
#layout p.byline {
|
||||
font-size: 12px;
|
||||
margin-top: 18px;
|
||||
line-height: 12px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
#layout p {
|
||||
font-size: 14px;
|
||||
line-height: 21px;
|
||||
margin-bottom: .5em;
|
||||
}
|
||||
|
||||
#layout p.large {
|
||||
font-size: 18px;
|
||||
line-height: 26px;
|
||||
}
|
||||
|
||||
#layout .sidebar p {
|
||||
font-size: 12px;
|
||||
line-height: 1.4em;
|
||||
}
|
||||
|
||||
#layout p.caption {
|
||||
font-size: 10px;
|
||||
margin-top: -16px;
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
|
||||
/* @end */
|
||||
|
||||
/* @group Glyphs */
|
||||
|
||||
#glyph_chart div {
|
||||
background-color: #d9f3ff;
|
||||
color: black;
|
||||
float: left;
|
||||
font-size: 36px;
|
||||
height: 1.2em;
|
||||
line-height: 1.2em;
|
||||
margin-bottom: 1px;
|
||||
margin-right: 1px;
|
||||
text-align: center;
|
||||
width: 1.2em;
|
||||
position: relative;
|
||||
padding: .6em .2em .2em;
|
||||
}
|
||||
|
||||
#glyph_chart div p {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
display: block;
|
||||
text-align: center;
|
||||
font: bold 9px Arial, sans-serif;
|
||||
background-color: #3a768f;
|
||||
width: 100%;
|
||||
color: #fff;
|
||||
padding: 2px 0;
|
||||
}
|
||||
|
||||
|
||||
#glyphs h1 {
|
||||
font-family: Arial, sans-serif;
|
||||
}
|
||||
|
||||
/* @end */
|
||||
|
||||
/* @group Installing */
|
||||
|
||||
#installing {
|
||||
font: 13px Arial, sans-serif;
|
||||
}
|
||||
|
||||
#installing p,
|
||||
#glyphs p {
|
||||
line-height: 1.2em;
|
||||
margin-bottom: 18px;
|
||||
font: 13px Arial, sans-serif;
|
||||
}
|
||||
|
||||
|
||||
#installing h3 {
|
||||
font-size: 15px;
|
||||
margin-top: 18px;
|
||||
}
|
||||
|
||||
/* @end */
|
||||
|
||||
#rendering h1 {
|
||||
font-family: Arial, sans-serif;
|
||||
}
|
||||
|
||||
.render_table td {
|
||||
font: 11px 'Courier New', Courier, mono;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
|
12
adminapi/www/cdn/chartegraphique/fonts/texte/stylesheet.css
Normal file
@ -0,0 +1,12 @@
|
||||
/*! Generated by Font Squirrel (https://www.fontsquirrel.com) on May 3, 2023 */
|
||||
|
||||
|
||||
|
||||
@font-face {
|
||||
font-family: 'questrialregular';
|
||||
src: url('questrial-regular-webfont.woff2') format('woff2'),
|
||||
url('questrial-regular-webfont.woff') format('woff');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
|
||||
}
|
BIN
adminapi/www/cdn/chartegraphique/logo/favicon.png
Normal file
After Width: | Height: | Size: 4.5 KiB |
BIN
adminapi/www/cdn/chartegraphique/logo/favicondark.png
Normal file
After Width: | Height: | Size: 4.5 KiB |
BIN
adminapi/www/cdn/chartegraphique/logo/faviconlight.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
BIN
adminapi/www/cdn/chartegraphique/logo/logobgdark.png
Normal file
After Width: | Height: | Size: 7.0 KiB |
168
adminapi/www/cdn/chartegraphique/logo/logobgdark.svg
Normal file
@ -0,0 +1,168 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="74.422066mm"
|
||||
height="39.408447mm"
|
||||
viewBox="0 0 74.422066 39.408447"
|
||||
version="1.1"
|
||||
id="svg5"
|
||||
inkscape:version="1.2.2 (732a01da63, 2022-12-09, custom)"
|
||||
sodipodi:docname="planchelogoapXtrib.svg"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview7"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:document-units="mm"
|
||||
showgrid="false"
|
||||
inkscape:zoom="2.3786088"
|
||||
inkscape:cx="429.03231"
|
||||
inkscape:cy="188.5556"
|
||||
inkscape:window-width="1868"
|
||||
inkscape:window-height="1141"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="layer1" />
|
||||
<defs
|
||||
id="defs2">
|
||||
<inkscape:path-effect
|
||||
effect="powerclip"
|
||||
id="path-effect4281-6"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
inverse="true"
|
||||
flatten="false"
|
||||
hide_clip="false"
|
||||
message="Utilise la règle de remplissage « fill-rule: evenodd » de la boîte de dialogue <b>Fond et contour</b> en l'absence de résultat de mise à plat après une conversion en chemin." />
|
||||
<inkscape:path-effect
|
||||
effect="powerclip"
|
||||
id="path-effect4223-1-5"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
inverse="true"
|
||||
flatten="false"
|
||||
hide_clip="false"
|
||||
message="Utilise la règle de remplissage « fill-rule: evenodd » de la boîte de dialogue <b>Fond et contour</b> en l'absence de résultat de mise à plat après une conversion en chemin." />
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipath_lpe_path-effect4281-6">
|
||||
<rect
|
||||
style="display:none;fill:none;stroke:#000000;stroke-width:2.965;stroke-miterlimit:5"
|
||||
id="rect12221"
|
||||
width="3.9103701"
|
||||
height="17.277628"
|
||||
x="72.929848"
|
||||
y="18.71629"
|
||||
d="m 72.929848,18.71629 h 3.91037 v 17.277627 h -3.91037 z" />
|
||||
<path
|
||||
id="lpe_path-effect4281-6"
|
||||
style="fill:none;stroke:#000000;stroke-width:2.965;stroke-miterlimit:5"
|
||||
class="powerclip"
|
||||
d="M 39.612377,7.7145809 H 79.612633 V 47.714838 H 39.612377 Z M 72.929848,18.71629 v 17.277627 h 3.91037 V 18.71629 Z" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipath_lpe_path-effect4223-1-5">
|
||||
<rect
|
||||
style="display:none;fill:none;stroke:#000000;stroke-width:0.890744;stroke-miterlimit:5;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect12226"
|
||||
width="29.109257"
|
||||
height="29.109257"
|
||||
x="45.057877"
|
||||
y="13.160081"
|
||||
clip-path="none"
|
||||
d="M 45.057877,13.160081 H 74.167133 V 42.269338 H 45.057877 Z" />
|
||||
<path
|
||||
id="lpe_path-effect4223-1-5"
|
||||
style="fill:none;stroke:#000000;stroke-width:0.890744;stroke-miterlimit:5;stroke-dasharray:none;stroke-opacity:1"
|
||||
class="powerclip"
|
||||
d="M 35.399339,3.8513256 H 75.39934 V 43.851326 H 35.399339 Z m 9.658538,9.3087554 V 42.269338 H 74.167133 V 13.160081 Z" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
<g
|
||||
inkscape:label="Calque 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-33.762223,-52.949721)">
|
||||
<rect
|
||||
style="fill:none;fill-opacity:1;stroke:none;stroke-width:0.264999;stroke-miterlimit:5;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect12066-9"
|
||||
width="74.422066"
|
||||
height="39.408443"
|
||||
x="33.685085"
|
||||
y="52.371716" />
|
||||
<rect
|
||||
style="fill:#ffffff;fill-opacity:0.0159938;stroke:none;stroke-width:0.264999;stroke-miterlimit:5;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect12066-6"
|
||||
width="74.422066"
|
||||
height="39.408443"
|
||||
x="33.762222"
|
||||
y="52.949718"
|
||||
inkscape:export-filename="../6e81e123/logobglight.svg"
|
||||
inkscape:export-xdpi="105.58897"
|
||||
inkscape:export-ydpi="105.58897" />
|
||||
<path
|
||||
style="display:block;fill:none;stroke:#ffffff;stroke-width:0.891;stroke-miterlimit:5;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect4221-6"
|
||||
width="29.109257"
|
||||
height="29.109257"
|
||||
x="45.057877"
|
||||
y="13.160081"
|
||||
clip-path="url(#clipath_lpe_path-effect4281-6)"
|
||||
inkscape:path-effect="#path-effect4281-6"
|
||||
d="M 45.057877,13.160081 H 74.167133 V 42.269338 H 45.057877 Z"
|
||||
sodipodi:type="rect"
|
||||
transform="translate(0.7877763,47.235812)" />
|
||||
<path
|
||||
style="display:block;fill:none;stroke:#ffffff;stroke-width:0.890744;stroke-miterlimit:5;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect4212-5-3"
|
||||
width="29.109257"
|
||||
height="29.109257"
|
||||
x="40.844711"
|
||||
y="9.2966976"
|
||||
clip-path="url(#clipath_lpe_path-effect4223-1-5)"
|
||||
inkscape:path-effect="#path-effect4223-1-5"
|
||||
d="M 40.844711,9.2966976 H 69.953968 V 38.405954 H 40.844711 Z"
|
||||
sodipodi:type="rect"
|
||||
transform="translate(1.2107703,47.421564)" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:3.175px;fill:#2e7fc8;fill-opacity:1;stroke-width:0.265;stroke-dasharray:none"
|
||||
x="48.645107"
|
||||
y="76.664268"
|
||||
id="text168-9"
|
||||
inkscape:highlight-color="#2e7fc8"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan166-4"
|
||||
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:14.1111px;font-family:Quicksand;-inkscape-font-specification:'Quicksand, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#2e7fc8;fill-opacity:1;stroke-width:0.265;stroke-dasharray:none"
|
||||
x="48.645107"
|
||||
y="76.664268"><tspan
|
||||
style="fill:#ffffff;fill-opacity:1"
|
||||
id="tspan12445">ap</tspan><tspan
|
||||
style="fill:#ffc332;fill-opacity:1"
|
||||
id="tspan11889-8">X</tspan><tspan
|
||||
style="fill:#ffffff;fill-opacity:0.985099"
|
||||
id="tspan12341">trib</tspan></tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#2e7fc8;fill-opacity:1;stroke-width:0.264583"
|
||||
x="54.550327"
|
||||
y="82.090439"
|
||||
id="text168-0-1"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan166-9-2"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#ffffff;fill-opacity:1;stroke-width:0.264583"
|
||||
x="54.550327"
|
||||
y="82.090439">BLOCKCHAIN OF DEMOCRACY</tspan></text>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 7.2 KiB |
BIN
adminapi/www/cdn/chartegraphique/logo/logobglight.png
Normal file
After Width: | Height: | Size: 10 KiB |
156
adminapi/www/cdn/chartegraphique/logo/logobglight.svg
Normal file
@ -0,0 +1,156 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="74.687065mm"
|
||||
height="39.673443mm"
|
||||
viewBox="0 0 74.687065 39.673443"
|
||||
version="1.1"
|
||||
id="svg5"
|
||||
inkscape:version="1.2.2 (732a01da63, 2022-12-09, custom)"
|
||||
sodipodi:docname="planchelogoapXtrib.svg"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview7"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:document-units="mm"
|
||||
showgrid="false"
|
||||
inkscape:zoom="2.3786088"
|
||||
inkscape:cx="429.03231"
|
||||
inkscape:cy="188.5556"
|
||||
inkscape:window-width="1868"
|
||||
inkscape:window-height="1141"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="layer1" />
|
||||
<defs
|
||||
id="defs2">
|
||||
<inkscape:path-effect
|
||||
effect="powerclip"
|
||||
id="path-effect4281"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
inverse="true"
|
||||
flatten="false"
|
||||
hide_clip="false"
|
||||
message="Utilise la règle de remplissage « fill-rule: evenodd » de la boîte de dialogue <b>Fond et contour</b> en l'absence de résultat de mise à plat après une conversion en chemin." />
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath4219-7">
|
||||
<rect
|
||||
style="display:none;fill:none;stroke:#000000;stroke-width:0.890744;stroke-miterlimit:5;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect4221-7"
|
||||
width="29.109257"
|
||||
height="29.109257"
|
||||
x="45.057877"
|
||||
y="13.160081"
|
||||
clip-path="none"
|
||||
d="M 45.057877,13.160081 H 74.167133 V 42.269338 H 45.057877 Z" />
|
||||
<path
|
||||
id="lpe_path-effect4223-1"
|
||||
style="fill:none;stroke:#000000;stroke-width:0.890744;stroke-miterlimit:5;stroke-dasharray:none;stroke-opacity:1"
|
||||
class="powerclip"
|
||||
d="M 35.399339,3.8513256 H 75.39934 V 43.851326 H 35.399339 Z m 9.658538,9.3087554 V 42.269338 H 74.167133 V 13.160081 Z" />
|
||||
</clipPath>
|
||||
<inkscape:path-effect
|
||||
effect="powerclip"
|
||||
id="path-effect4223-1"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
inverse="true"
|
||||
flatten="false"
|
||||
hide_clip="false"
|
||||
message="Utilise la règle de remplissage « fill-rule: evenodd » de la boîte de dialogue <b>Fond et contour</b> en l'absence de résultat de mise à plat après une conversion en chemin." />
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath4277">
|
||||
<rect
|
||||
style="display:none;fill:none;stroke:#000000;stroke-width:2.965;stroke-miterlimit:5"
|
||||
id="rect4279"
|
||||
width="3.9103701"
|
||||
height="17.277628"
|
||||
x="72.929848"
|
||||
y="18.71629"
|
||||
d="m 72.929848,18.71629 h 3.91037 v 17.277627 h -3.91037 z" />
|
||||
<path
|
||||
id="lpe_path-effect4281"
|
||||
style="fill:none;stroke:#000000;stroke-width:2.965;stroke-miterlimit:5"
|
||||
class="powerclip"
|
||||
d="M 39.612377,7.7145809 H 79.612633 V 47.714838 H 39.612377 Z M 72.929848,18.71629 v 17.277627 h 3.91037 V 18.71629 Z" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
<g
|
||||
inkscape:label="Calque 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-32.764809,-5.0034045)">
|
||||
<path
|
||||
style="display:block;fill:none;stroke:#2e7fc8;stroke-width:0.891;stroke-miterlimit:5;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect4221"
|
||||
width="29.109257"
|
||||
height="29.109257"
|
||||
x="45.057877"
|
||||
y="13.160081"
|
||||
clip-path="url(#clipPath4277)"
|
||||
inkscape:path-effect="#path-effect4281"
|
||||
d="M 45.057877,13.160081 H 74.167133 V 42.269338 H 45.057877 Z"
|
||||
sodipodi:type="rect" />
|
||||
<path
|
||||
style="display:block;fill:none;stroke:#2e7fc8;stroke-width:0.890744;stroke-miterlimit:5;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect4212-5"
|
||||
width="29.109257"
|
||||
height="29.109257"
|
||||
x="40.844711"
|
||||
y="9.2966976"
|
||||
clip-path="url(#clipPath4219-7)"
|
||||
inkscape:path-effect="#path-effect4223-1"
|
||||
d="M 40.844711,9.2966976 H 69.953968 V 38.405954 H 40.844711 Z"
|
||||
sodipodi:type="rect"
|
||||
transform="translate(0.42299389,0.18575204)" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:3.175px;fill:#2e7fc8;fill-opacity:1;stroke-width:0.265;stroke-dasharray:none"
|
||||
x="47.857334"
|
||||
y="29.428459"
|
||||
id="text168"
|
||||
inkscape:highlight-color="#2e7fc8"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan166"
|
||||
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:14.1111px;font-family:Quicksand;-inkscape-font-specification:'Quicksand, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#2e7fc8;fill-opacity:1;stroke-width:0.265;stroke-dasharray:none"
|
||||
x="47.857334"
|
||||
y="29.428459">ap<tspan
|
||||
style="fill:#ffc332;fill-opacity:1"
|
||||
id="tspan11889">X</tspan>trib</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#2e7fc8;fill-opacity:1;stroke-width:0.264583"
|
||||
x="53.762562"
|
||||
y="34.85463"
|
||||
id="text168-0"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan166-9"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#2e7fc8;fill-opacity:1;stroke-width:0.264583"
|
||||
x="53.762562"
|
||||
y="34.85463">BLOCKCHAIN OF DEMOCRACY</tspan></text>
|
||||
<rect
|
||||
style="fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:0.264999;stroke-miterlimit:5;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect12066"
|
||||
width="74.422066"
|
||||
height="39.408443"
|
||||
x="32.897308"
|
||||
y="5.1359038"
|
||||
inkscape:export-filename="../6e81e123/logobglight.svg"
|
||||
inkscape:export-xdpi="105.58897"
|
||||
inkscape:export-ydpi="105.58897" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 6.6 KiB |
BIN
adminapi/www/cdn/chartegraphique/logo/logocarredark.png
Normal file
After Width: | Height: | Size: 4.5 KiB |
BIN
adminapi/www/cdn/chartegraphique/logo/logocarrelight.png
Normal file
After Width: | Height: | Size: 4.2 KiB |
779
adminapi/www/cdn/chartegraphique/plancheavatarpagan.svg
Normal file
@ -0,0 +1,779 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="210mm"
|
||||
height="297mm"
|
||||
viewBox="0 0 210 297"
|
||||
version="1.1"
|
||||
id="svg7077"
|
||||
inkscape:version="1.2.2 (732a01da63, 2022-12-09, custom)"
|
||||
sodipodi:docname="plancheavatarpagan.svg"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview7079"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:document-units="mm"
|
||||
showgrid="false"
|
||||
inkscape:zoom="1.1893044"
|
||||
inkscape:cx="484.73713"
|
||||
inkscape:cy="244.26043"
|
||||
inkscape:window-width="1868"
|
||||
inkscape:window-height="1141"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="layer1" />
|
||||
<defs
|
||||
id="defs7074">
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipath_lpe_path-effect4223-1-4-9">
|
||||
<rect
|
||||
style="display:none;fill:none;stroke:#000000;stroke-width:0.890744;stroke-miterlimit:5;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect6741"
|
||||
width="29.109257"
|
||||
height="29.109257"
|
||||
x="45.057877"
|
||||
y="13.160081"
|
||||
clip-path="none"
|
||||
d="M 45.057877,13.160081 H 74.167133 V 42.269338 H 45.057877 Z" />
|
||||
<path
|
||||
id="lpe_path-effect4223-1-4-9"
|
||||
style="fill:none;stroke:#000000;stroke-width:0.890744;stroke-miterlimit:5;stroke-dasharray:none;stroke-opacity:1"
|
||||
class="powerclip"
|
||||
d="M 35.399339,3.8513256 H 75.39934 V 43.851326 H 35.399339 Z m 9.658538,9.3087554 V 42.269338 H 74.167133 V 13.160081 Z" />
|
||||
</clipPath>
|
||||
<inkscape:path-effect
|
||||
effect="powerclip"
|
||||
id="path-effect4223-1-4-9"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
inverse="true"
|
||||
flatten="false"
|
||||
hide_clip="false"
|
||||
message="Utilise la règle de remplissage « fill-rule: evenodd » de la boîte de dialogue <b>Fond et contour</b> en l'absence de résultat de mise à plat après une conversion en chemin." />
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipath_lpe_path-effect4281-3-5">
|
||||
<rect
|
||||
style="display:none;fill:none;stroke:#000000;stroke-width:2.965;stroke-miterlimit:5"
|
||||
id="rect6689"
|
||||
width="3.9103701"
|
||||
height="17.277628"
|
||||
x="72.929848"
|
||||
y="18.71629"
|
||||
d="m 72.929848,18.71629 h 3.91037 v 17.277627 h -3.91037 z" />
|
||||
<path
|
||||
id="lpe_path-effect4281-3-5"
|
||||
style="fill:none;stroke:#000000;stroke-width:2.965;stroke-miterlimit:5"
|
||||
class="powerclip"
|
||||
d="M 39.612377,7.7145809 H 79.612633 V 47.714838 H 39.612377 Z M 72.929848,18.71629 v 17.277627 h 3.91037 V 18.71629 Z" />
|
||||
</clipPath>
|
||||
<inkscape:path-effect
|
||||
effect="powerclip"
|
||||
id="path-effect4281-3-5"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
inverse="true"
|
||||
flatten="false"
|
||||
hide_clip="false"
|
||||
message="Utilise la règle de remplissage « fill-rule: evenodd » de la boîte de dialogue <b>Fond et contour</b> en l'absence de résultat de mise à plat après une conversion en chemin." />
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipath_lpe_path-effect4223-1-4-9-9">
|
||||
<rect
|
||||
style="display:none;fill:none;stroke:#000000;stroke-width:0.890744;stroke-miterlimit:5;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect6741-3"
|
||||
width="29.109257"
|
||||
height="29.109257"
|
||||
x="45.057877"
|
||||
y="13.160081"
|
||||
clip-path="none"
|
||||
d="M 45.057877,13.160081 H 74.167133 V 42.269338 H 45.057877 Z" />
|
||||
<path
|
||||
id="lpe_path-effect4223-1-4-9-6"
|
||||
style="fill:none;stroke:#000000;stroke-width:0.890744;stroke-miterlimit:5;stroke-dasharray:none;stroke-opacity:1"
|
||||
class="powerclip"
|
||||
d="M 35.399339,3.8513256 H 75.39934 V 43.851326 H 35.399339 Z m 9.658538,9.3087554 V 42.269338 H 74.167133 V 13.160081 Z" />
|
||||
</clipPath>
|
||||
<inkscape:path-effect
|
||||
effect="powerclip"
|
||||
id="path-effect4223-1-4-9-0"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
inverse="true"
|
||||
flatten="false"
|
||||
hide_clip="false"
|
||||
message="Utilise la règle de remplissage « fill-rule: evenodd » de la boîte de dialogue <b>Fond et contour</b> en l'absence de résultat de mise à plat après une conversion en chemin." />
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipath_lpe_path-effect4281-3-5-6">
|
||||
<rect
|
||||
style="display:none;fill:none;stroke:#000000;stroke-width:2.965;stroke-miterlimit:5"
|
||||
id="rect6689-2"
|
||||
width="3.9103701"
|
||||
height="17.277628"
|
||||
x="72.929848"
|
||||
y="18.71629"
|
||||
d="m 72.929848,18.71629 h 3.91037 v 17.277627 h -3.91037 z" />
|
||||
<path
|
||||
id="lpe_path-effect4281-3-5-6"
|
||||
style="fill:none;stroke:#000000;stroke-width:2.965;stroke-miterlimit:5"
|
||||
class="powerclip"
|
||||
d="M 39.612377,7.7145809 H 79.612633 V 47.714838 H 39.612377 Z M 72.929848,18.71629 v 17.277627 h 3.91037 V 18.71629 Z" />
|
||||
</clipPath>
|
||||
<inkscape:path-effect
|
||||
effect="powerclip"
|
||||
id="path-effect4281-3-5-1"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
inverse="true"
|
||||
flatten="false"
|
||||
hide_clip="false"
|
||||
message="Utilise la règle de remplissage « fill-rule: evenodd » de la boîte de dialogue <b>Fond et contour</b> en l'absence de résultat de mise à plat après une conversion en chemin." />
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipath_lpe_path-effect4223-1-4-9-0">
|
||||
<rect
|
||||
style="display:none;fill:none;stroke:#000000;stroke-width:0.890744;stroke-miterlimit:5;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect9685"
|
||||
width="29.109257"
|
||||
height="29.109257"
|
||||
x="45.057877"
|
||||
y="13.160081"
|
||||
clip-path="none"
|
||||
d="M 45.057877,13.160081 H 74.167133 V 42.269338 H 45.057877 Z" />
|
||||
<path
|
||||
id="lpe_path-effect4223-1-4-9-0"
|
||||
style="fill:none;stroke:#000000;stroke-width:0.890744;stroke-miterlimit:5;stroke-dasharray:none;stroke-opacity:1"
|
||||
class="powerclip"
|
||||
d="M 35.399339,3.8513256 H 75.39934 V 43.851326 H 35.399339 Z m 9.658538,9.3087554 V 42.269338 H 74.167133 V 13.160081 Z" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipath_lpe_path-effect4281-3-5-1">
|
||||
<rect
|
||||
style="display:none;fill:none;stroke:#000000;stroke-width:2.965;stroke-miterlimit:5"
|
||||
id="rect9690"
|
||||
width="3.9103701"
|
||||
height="17.277628"
|
||||
x="72.929848"
|
||||
y="18.71629"
|
||||
d="m 72.929848,18.71629 h 3.91037 v 17.277627 h -3.91037 z" />
|
||||
<path
|
||||
id="lpe_path-effect4281-3-5-1"
|
||||
style="fill:none;stroke:#000000;stroke-width:2.965;stroke-miterlimit:5"
|
||||
class="powerclip"
|
||||
d="M 39.612377,7.7145809 H 79.612633 V 47.714838 H 39.612377 Z M 72.929848,18.71629 v 17.277627 h 3.91037 V 18.71629 Z" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipath_lpe_path-effect4223-1-4-9-0-9">
|
||||
<rect
|
||||
style="display:none;fill:none;stroke:#000000;stroke-width:0.890744;stroke-miterlimit:5;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect9685-3"
|
||||
width="29.109257"
|
||||
height="29.109257"
|
||||
x="45.057877"
|
||||
y="13.160081"
|
||||
clip-path="none"
|
||||
d="M 45.057877,13.160081 H 74.167133 V 42.269338 H 45.057877 Z" />
|
||||
<path
|
||||
id="lpe_path-effect4223-1-4-9-0-1"
|
||||
style="fill:none;stroke:#000000;stroke-width:0.890744;stroke-miterlimit:5;stroke-dasharray:none;stroke-opacity:1"
|
||||
class="powerclip"
|
||||
d="M 35.399339,3.8513256 H 75.39934 V 43.851326 H 35.399339 Z m 9.658538,9.3087554 V 42.269338 H 74.167133 V 13.160081 Z" />
|
||||
</clipPath>
|
||||
<inkscape:path-effect
|
||||
effect="powerclip"
|
||||
id="path-effect4223-1-4-9-0-9"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
inverse="true"
|
||||
flatten="false"
|
||||
hide_clip="false"
|
||||
message="Utilise la règle de remplissage « fill-rule: evenodd » de la boîte de dialogue <b>Fond et contour</b> en l'absence de résultat de mise à plat après une conversion en chemin." />
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipath_lpe_path-effect4281-3-5-1-4">
|
||||
<rect
|
||||
style="display:none;fill:none;stroke:#000000;stroke-width:2.965;stroke-miterlimit:5"
|
||||
id="rect9690-7"
|
||||
width="3.9103701"
|
||||
height="17.277628"
|
||||
x="72.929848"
|
||||
y="18.71629"
|
||||
d="m 72.929848,18.71629 h 3.91037 v 17.277627 h -3.91037 z" />
|
||||
<path
|
||||
id="lpe_path-effect4281-3-5-1-8"
|
||||
style="fill:none;stroke:#000000;stroke-width:2.965;stroke-miterlimit:5"
|
||||
class="powerclip"
|
||||
d="M 39.612377,7.7145809 H 79.612633 V 47.714838 H 39.612377 Z M 72.929848,18.71629 v 17.277627 h 3.91037 V 18.71629 Z" />
|
||||
</clipPath>
|
||||
<inkscape:path-effect
|
||||
effect="powerclip"
|
||||
id="path-effect4281-3-5-1-4"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
inverse="true"
|
||||
flatten="false"
|
||||
hide_clip="false"
|
||||
message="Utilise la règle de remplissage « fill-rule: evenodd » de la boîte de dialogue <b>Fond et contour</b> en l'absence de résultat de mise à plat après une conversion en chemin." />
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath10785">
|
||||
<rect
|
||||
style="display:none;fill:none;stroke:#000000;stroke-width:0.890744;stroke-miterlimit:5;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect10781"
|
||||
width="29.109257"
|
||||
height="29.109257"
|
||||
x="45.057877"
|
||||
y="13.160081"
|
||||
clip-path="none"
|
||||
d="M 45.057877,13.160081 H 74.167133 V 42.269338 H 45.057877 Z" />
|
||||
<path
|
||||
id="lpe_path-effect4223-1-4-9-0-9"
|
||||
style="fill:none;stroke:#000000;stroke-width:0.890744;stroke-miterlimit:5;stroke-dasharray:none;stroke-opacity:1"
|
||||
class="powerclip"
|
||||
d="M 35.399339,3.8513256 H 75.39934 V 43.851326 H 35.399339 Z m 9.658538,9.3087554 V 42.269338 H 74.167133 V 13.160081 Z" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath10791">
|
||||
<rect
|
||||
style="display:none;fill:none;stroke:#000000;stroke-width:2.965;stroke-miterlimit:5"
|
||||
id="rect10787"
|
||||
width="3.9103701"
|
||||
height="17.277628"
|
||||
x="72.929848"
|
||||
y="18.71629"
|
||||
d="m 72.929848,18.71629 h 3.91037 v 17.277627 h -3.91037 z" />
|
||||
<path
|
||||
id="lpe_path-effect4281-3-5-1-4"
|
||||
style="fill:none;stroke:#000000;stroke-width:2.965;stroke-miterlimit:5"
|
||||
class="powerclip"
|
||||
d="M 39.612377,7.7145809 H 79.612633 V 47.714838 H 39.612377 Z M 72.929848,18.71629 v 17.277627 h 3.91037 V 18.71629 Z" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipath_lpe_path-effect4223-1-4-9-0-9-6">
|
||||
<rect
|
||||
style="display:none;fill:none;stroke:#000000;stroke-width:0.890744;stroke-miterlimit:5;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect9685-3-5"
|
||||
width="29.109257"
|
||||
height="29.109257"
|
||||
x="45.057877"
|
||||
y="13.160081"
|
||||
clip-path="none"
|
||||
d="M 45.057877,13.160081 H 74.167133 V 42.269338 H 45.057877 Z" />
|
||||
<path
|
||||
id="lpe_path-effect4223-1-4-9-0-1-6"
|
||||
style="fill:none;stroke:#000000;stroke-width:0.890744;stroke-miterlimit:5;stroke-dasharray:none;stroke-opacity:1"
|
||||
class="powerclip"
|
||||
d="M 35.399339,3.8513256 H 75.39934 V 43.851326 H 35.399339 Z m 9.658538,9.3087554 V 42.269338 H 74.167133 V 13.160081 Z" />
|
||||
</clipPath>
|
||||
<inkscape:path-effect
|
||||
effect="powerclip"
|
||||
id="path-effect4223-1-4-9-0-9-9"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
inverse="true"
|
||||
flatten="false"
|
||||
hide_clip="false"
|
||||
message="Utilise la règle de remplissage « fill-rule: evenodd » de la boîte de dialogue <b>Fond et contour</b> en l'absence de résultat de mise à plat après une conversion en chemin." />
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipath_lpe_path-effect4281-3-5-1-4-3">
|
||||
<rect
|
||||
style="display:none;fill:none;stroke:#000000;stroke-width:2.965;stroke-miterlimit:5"
|
||||
id="rect9690-7-7"
|
||||
width="3.9103701"
|
||||
height="17.277628"
|
||||
x="72.929848"
|
||||
y="18.71629"
|
||||
d="m 72.929848,18.71629 h 3.91037 v 17.277627 h -3.91037 z" />
|
||||
<path
|
||||
id="lpe_path-effect4281-3-5-1-8-4"
|
||||
style="fill:none;stroke:#000000;stroke-width:2.965;stroke-miterlimit:5"
|
||||
class="powerclip"
|
||||
d="M 39.612377,7.7145809 H 79.612633 V 47.714838 H 39.612377 Z M 72.929848,18.71629 v 17.277627 h 3.91037 V 18.71629 Z" />
|
||||
</clipPath>
|
||||
<inkscape:path-effect
|
||||
effect="powerclip"
|
||||
id="path-effect4281-3-5-1-4-5"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
inverse="true"
|
||||
flatten="false"
|
||||
hide_clip="false"
|
||||
message="Utilise la règle de remplissage « fill-rule: evenodd » de la boîte de dialogue <b>Fond et contour</b> en l'absence de résultat de mise à plat après une conversion en chemin." />
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath11673">
|
||||
<rect
|
||||
style="display:none;fill:none;stroke:#000000;stroke-width:0.890744;stroke-miterlimit:5;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect11669"
|
||||
width="29.109257"
|
||||
height="29.109257"
|
||||
x="45.057877"
|
||||
y="13.160081"
|
||||
clip-path="none"
|
||||
d="M 45.057877,13.160081 H 74.167133 V 42.269338 H 45.057877 Z" />
|
||||
<path
|
||||
id="lpe_path-effect4223-1-4-9-0-9-2"
|
||||
style="fill:none;stroke:#000000;stroke-width:0.890744;stroke-miterlimit:5;stroke-dasharray:none;stroke-opacity:1"
|
||||
class="powerclip"
|
||||
d="M 35.399339,3.8513256 H 75.39934 V 43.851326 H 35.399339 Z m 9.658538,9.3087554 V 42.269338 H 74.167133 V 13.160081 Z" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath11679">
|
||||
<rect
|
||||
style="display:none;fill:none;stroke:#000000;stroke-width:2.965;stroke-miterlimit:5"
|
||||
id="rect11675"
|
||||
width="3.9103701"
|
||||
height="17.277628"
|
||||
x="72.929848"
|
||||
y="18.71629"
|
||||
d="m 72.929848,18.71629 h 3.91037 v 17.277627 h -3.91037 z" />
|
||||
<path
|
||||
id="lpe_path-effect4281-3-5-1-4-5"
|
||||
style="fill:none;stroke:#000000;stroke-width:2.965;stroke-miterlimit:5"
|
||||
class="powerclip"
|
||||
d="M 39.612377,7.7145809 H 79.612633 V 47.714838 H 39.612377 Z M 72.929848,18.71629 v 17.277627 h 3.91037 V 18.71629 Z" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipath_lpe_path-effect4223-1-4-9-0-9-9">
|
||||
<rect
|
||||
style="display:none;fill:none;stroke:#000000;stroke-width:0.890744;stroke-miterlimit:5;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect11814"
|
||||
width="29.109257"
|
||||
height="29.109257"
|
||||
x="45.057877"
|
||||
y="13.160081"
|
||||
clip-path="none"
|
||||
d="M 45.057877,13.160081 H 74.167133 V 42.269338 H 45.057877 Z" />
|
||||
<path
|
||||
id="lpe_path-effect4223-1-4-9-0-9-9"
|
||||
style="fill:none;stroke:#000000;stroke-width:0.890744;stroke-miterlimit:5;stroke-dasharray:none;stroke-opacity:1"
|
||||
class="powerclip"
|
||||
d="M 35.399339,3.8513256 H 75.39934 V 43.851326 H 35.399339 Z m 9.658538,9.3087554 V 42.269338 H 74.167133 V 13.160081 Z" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
<g
|
||||
inkscape:label="Calque 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1">
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:3.175px;fill:#2e7fc8;fill-opacity:1;stroke-width:0.265;stroke-dasharray:none"
|
||||
x="45.127651"
|
||||
y="37.870438"
|
||||
id="text168-8-2"
|
||||
inkscape:highlight-color="#2e7fc8"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan166-97-7"
|
||||
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:14.1111px;font-family:Quicksand;-inkscape-font-specification:'Quicksand, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#2e7fc8;fill-opacity:1;stroke-width:0.265;stroke-dasharray:none"
|
||||
x="45.127651"
|
||||
y="37.870438"><tspan
|
||||
style="fill:#ffc332;fill-opacity:1"
|
||||
id="tspan11889-7-0">X</tspan></tspan></text>
|
||||
<path
|
||||
style="display:block;fill:none;stroke:#2e7fc8;stroke-width:0.890744;stroke-miterlimit:5;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect4212-5-8-1"
|
||||
width="29.109257"
|
||||
height="29.109257"
|
||||
x="40.844711"
|
||||
y="9.2966976"
|
||||
clip-path="url(#clipath_lpe_path-effect4223-1-4-9)"
|
||||
inkscape:path-effect="#path-effect4223-1-4-9"
|
||||
d="M 40.844711,9.2966976 H 69.953968 V 38.405954 H 40.844711 Z"
|
||||
sodipodi:type="rect"
|
||||
transform="translate(-25.528762,6.2122106)" />
|
||||
<path
|
||||
style="display:block;fill:none;stroke:#2e7fc8;stroke-width:0.891;stroke-miterlimit:5;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect4221-8-3"
|
||||
width="29.109257"
|
||||
height="29.109257"
|
||||
x="45.057877"
|
||||
y="13.160081"
|
||||
clip-path="url(#clipath_lpe_path-effect4281-3-5)"
|
||||
inkscape:path-effect="#path-effect4281-3-5"
|
||||
d="M 45.057877,13.160081 H 74.167133 V 42.269338 H 45.057877 Z"
|
||||
sodipodi:type="rect"
|
||||
transform="translate(-24.666854,6.5783446)"
|
||||
inkscape:export-filename="../36533220/favicon.png"
|
||||
inkscape:export-xdpi="105.58897"
|
||||
inkscape:export-ydpi="105.58897" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:3.175px;fill:#2e7fc8;fill-opacity:1;stroke-width:0.265;stroke-dasharray:none"
|
||||
x="48.900738"
|
||||
y="84.014198"
|
||||
id="text168-8-2-8"
|
||||
inkscape:highlight-color="#2e7fc8"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan166-97-7-7"
|
||||
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:14.1111px;font-family:Quicksand;-inkscape-font-specification:'Quicksand, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#2e7fc8;fill-opacity:1;stroke-width:0.265;stroke-dasharray:none"
|
||||
x="48.900738"
|
||||
y="84.014198"><tspan
|
||||
style="fill:#ffc332;fill-opacity:1"
|
||||
id="tspan11889-7-0-9">X</tspan></tspan></text>
|
||||
<path
|
||||
style="display:block;fill:none;stroke:#6aa84f;stroke-width:0.890744;stroke-miterlimit:5;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect4212-5-8-1-2"
|
||||
width="29.109257"
|
||||
height="29.109257"
|
||||
x="40.844711"
|
||||
y="9.2966976"
|
||||
clip-path="url(#clipath_lpe_path-effect4223-1-4-9-0)"
|
||||
inkscape:path-effect="#path-effect4223-1-4-9-0"
|
||||
d="M 40.844711,9.2966976 H 69.953968 V 38.405954 H 40.844711 Z"
|
||||
sodipodi:type="rect"
|
||||
transform="translate(-21.755675,52.355967)" />
|
||||
<path
|
||||
style="display:block;fill:none;stroke:#6aa84f;stroke-width:0.891;stroke-miterlimit:5;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect4221-8-3-0"
|
||||
width="29.109257"
|
||||
height="29.109257"
|
||||
x="45.057877"
|
||||
y="13.160081"
|
||||
clip-path="url(#clipath_lpe_path-effect4281-3-5-1)"
|
||||
inkscape:path-effect="#path-effect4281-3-5-1"
|
||||
d="M 45.057877,13.160081 H 74.167133 V 42.269338 H 45.057877 Z"
|
||||
sodipodi:type="rect"
|
||||
transform="translate(-20.893767,52.722101)"
|
||||
inkscape:export-filename="../36533220/favicon.png"
|
||||
inkscape:export-xdpi="105.58897"
|
||||
inkscape:export-ydpi="105.58897" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:2.82223px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';fill:#dedede;fill-opacity:0.704313;stroke-width:0.264999;stroke-miterlimit:5"
|
||||
x="78.410744"
|
||||
y="22.720804"
|
||||
id="text7650"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan7648"
|
||||
style="stroke-width:0.265"
|
||||
x="78.410744"
|
||||
y="22.720804"><tspan
|
||||
style="fill:none;stroke:#2e7fc8;stroke-opacity:1"
|
||||
id="tspan8015">Ajouter un qrcode à partir cle public</tspan> </tspan><tspan
|
||||
sodipodi:role="line"
|
||||
style="stroke:#2e7fc8;stroke-width:0.265;stroke-opacity:1"
|
||||
x="78.410744"
|
||||
y="26.248592"
|
||||
id="tspan9577" /><tspan
|
||||
sodipodi:role="line"
|
||||
style="stroke:#2e7fc8;stroke-width:0.265;stroke-opacity:1"
|
||||
x="78.410744"
|
||||
y="29.776379"
|
||||
id="tspan9579">Utiliser https://github.com/datalog/qrcode-svg pour convertir la cle public en QR</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
style="stroke:#2e7fc8;stroke-width:0.265;stroke-opacity:1"
|
||||
x="78.410744"
|
||||
y="33.304169"
|
||||
id="tspan9581" /><tspan
|
||||
sodipodi:role="line"
|
||||
style="stroke:#2e7fc8;stroke-width:0.265;stroke-opacity:1"
|
||||
x="78.410744"
|
||||
y="36.831955"
|
||||
id="tspan9583">Avec un lien qui permet d'envoyer un message </tspan><tspan
|
||||
sodipodi:role="line"
|
||||
style="stroke:#2e7fc8;stroke-width:0.265;stroke-opacity:1"
|
||||
x="78.410744"
|
||||
y="40.359741"
|
||||
id="tspan9585" /><tspan
|
||||
sodipodi:role="line"
|
||||
style="stroke:#2e7fc8;stroke-width:0.265;stroke-opacity:1"
|
||||
x="78.410744"
|
||||
y="43.887531"
|
||||
id="tspan9587">On garde le bleu pour l'action d'envoyer un message ou une transaction à ce pagan </tspan><tspan
|
||||
sodipodi:role="line"
|
||||
style="stroke:#2e7fc8;stroke-width:0.265;stroke-opacity:1"
|
||||
x="78.410744"
|
||||
y="47.415318"
|
||||
id="tspan9589" /><tspan
|
||||
sodipodi:role="line"
|
||||
style="stroke:#2e7fc8;stroke-width:0.265;stroke-opacity:1"
|
||||
x="78.410744"
|
||||
y="50.943104"
|
||||
id="tspan9591" /><tspan
|
||||
sodipodi:role="line"
|
||||
style="stroke:#2e7fc8;stroke-width:0.265;stroke-opacity:1"
|
||||
x="78.410744"
|
||||
y="54.470894"
|
||||
id="tspan9593" /><tspan
|
||||
sodipodi:role="line"
|
||||
style="stroke:#2e7fc8;stroke-width:0.265;stroke-opacity:1"
|
||||
x="78.410744"
|
||||
y="57.99868"
|
||||
id="tspan9595" /><tspan
|
||||
sodipodi:role="line"
|
||||
style="stroke:#2e7fc8;stroke-width:0.265;stroke-opacity:1"
|
||||
x="78.410744"
|
||||
y="61.526466"
|
||||
id="tspan9597" /></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:2.82223px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';fill:#dedede;fill-opacity:0.704313;stroke-width:0.264999;stroke-miterlimit:5"
|
||||
x="77.256157"
|
||||
y="64.232224"
|
||||
id="text7650-2"><tspan
|
||||
sodipodi:role="line"
|
||||
style="stroke:#2e7fc8;stroke-width:0.265;stroke-opacity:1"
|
||||
x="77.256157"
|
||||
y="64.232224"
|
||||
id="tspan9579-9" /><tspan
|
||||
sodipodi:role="line"
|
||||
style="stroke:#2e7fc8;stroke-width:0.265;stroke-opacity:1"
|
||||
x="77.256157"
|
||||
y="67.76001"
|
||||
id="tspan9581-2" /><tspan
|
||||
sodipodi:role="line"
|
||||
style="stroke:#6aa84f;stroke-width:0.265;stroke-opacity:1"
|
||||
x="77.256157"
|
||||
y="71.287796"
|
||||
id="tspan9583-2">Avec un lien qui permet d'envoyer un message à tous les membres d'une tribut </tspan><tspan
|
||||
sodipodi:role="line"
|
||||
style="stroke:#6aa84f;stroke-width:0.265;stroke-opacity:1"
|
||||
x="77.256157"
|
||||
y="74.81559"
|
||||
id="tspan9585-8" /><tspan
|
||||
sodipodi:role="line"
|
||||
style="stroke:#6aa84f;stroke-width:0.265;stroke-opacity:1"
|
||||
x="77.256157"
|
||||
y="78.343376"
|
||||
id="tspan9587-9">On garde le vert pour les tributs</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
style="stroke:#2e7fc8;stroke-width:0.265;stroke-opacity:1"
|
||||
x="77.256157"
|
||||
y="81.871162"
|
||||
id="tspan9589-7" /><tspan
|
||||
sodipodi:role="line"
|
||||
style="stroke:#2e7fc8;stroke-width:0.265;stroke-opacity:1"
|
||||
x="77.256157"
|
||||
y="85.398949"
|
||||
id="tspan9591-3" /><tspan
|
||||
sodipodi:role="line"
|
||||
style="stroke:#2e7fc8;stroke-width:0.265;stroke-opacity:1"
|
||||
x="77.256157"
|
||||
y="88.926735"
|
||||
id="tspan9593-6" /><tspan
|
||||
sodipodi:role="line"
|
||||
style="stroke:#2e7fc8;stroke-width:0.265;stroke-opacity:1"
|
||||
x="77.256157"
|
||||
y="92.454521"
|
||||
id="tspan9595-1" /><tspan
|
||||
sodipodi:role="line"
|
||||
style="stroke:#2e7fc8;stroke-width:0.265;stroke-opacity:1"
|
||||
x="77.256157"
|
||||
y="95.982315"
|
||||
id="tspan9597-2" /></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:3.175px;fill:#2e7fc8;fill-opacity:1;stroke-width:0.265;stroke-dasharray:none"
|
||||
x="51.181778"
|
||||
y="134.55898"
|
||||
id="text168-8-2-8-5"
|
||||
inkscape:highlight-color="#2e7fc8"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan166-97-7-7-0"
|
||||
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:14.1111px;font-family:Quicksand;-inkscape-font-specification:'Quicksand, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#2e7fc8;fill-opacity:1;stroke-width:0.265;stroke-dasharray:none"
|
||||
x="51.181778"
|
||||
y="134.55898"><tspan
|
||||
style="fill:#ffc332;fill-opacity:1"
|
||||
id="tspan11889-7-0-9-3">X</tspan></tspan></text>
|
||||
<path
|
||||
style="display:block;fill:none;stroke:#fa6a31;stroke-width:0.890744;stroke-miterlimit:5;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect4212-5-8-1-2-6"
|
||||
width="29.109257"
|
||||
height="29.109257"
|
||||
x="40.844711"
|
||||
y="9.2966976"
|
||||
clip-path="url(#clipath_lpe_path-effect4223-1-4-9-0-9)"
|
||||
inkscape:path-effect="#path-effect4223-1-4-9-0-9"
|
||||
d="M 40.844711,9.2966976 H 69.953968 V 38.405954 H 40.844711 Z"
|
||||
sodipodi:type="rect"
|
||||
transform="translate(-19.474638,102.90074)" />
|
||||
<path
|
||||
style="display:block;fill:none;stroke:#fa6a31;stroke-width:0.891;stroke-miterlimit:5;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect4221-8-3-0-1"
|
||||
width="29.109257"
|
||||
height="29.109257"
|
||||
x="45.057877"
|
||||
y="13.160081"
|
||||
clip-path="url(#clipath_lpe_path-effect4281-3-5-1-4)"
|
||||
inkscape:path-effect="#path-effect4281-3-5-1-4"
|
||||
d="M 45.057877,13.160081 H 74.167133 V 42.269338 H 45.057877 Z"
|
||||
sodipodi:type="rect"
|
||||
transform="translate(-18.612728,103.26688)"
|
||||
inkscape:export-filename="../36533220/favicon.png"
|
||||
inkscape:export-xdpi="105.58897"
|
||||
inkscape:export-ydpi="105.58897" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:2.82223px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';fill:#dedede;fill-opacity:0.704313;stroke-width:0.264999;stroke-miterlimit:5"
|
||||
x="79.537201"
|
||||
y="114.777"
|
||||
id="text7650-2-0"><tspan
|
||||
sodipodi:role="line"
|
||||
style="stroke:#2e7fc8;stroke-width:0.265;stroke-opacity:1"
|
||||
x="79.537201"
|
||||
y="114.777"
|
||||
id="tspan9579-9-6" /><tspan
|
||||
sodipodi:role="line"
|
||||
style="stroke:#fa6a31;stroke-width:0.265;stroke-opacity:1"
|
||||
x="79.537201"
|
||||
y="118.30479"
|
||||
id="tspan9581-2-3" /><tspan
|
||||
sodipodi:role="line"
|
||||
style="stroke:#fa6a31;stroke-width:0.265;stroke-opacity:1"
|
||||
x="79.537201"
|
||||
y="121.83257"
|
||||
id="tspan9583-2-2">Avec un lien qui permet d'envoyer un message à tous les membres d'une town </tspan><tspan
|
||||
sodipodi:role="line"
|
||||
style="stroke:#fa6a31;stroke-width:0.265;stroke-opacity:1"
|
||||
x="79.537201"
|
||||
y="125.36037"
|
||||
id="tspan9585-8-0" /><tspan
|
||||
sodipodi:role="line"
|
||||
style="stroke:#fa6a31;stroke-width:0.265;stroke-opacity:1"
|
||||
x="79.537201"
|
||||
y="128.88815"
|
||||
id="tspan9587-9-6">On garde le orange pour les towns</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
style="stroke:#2e7fc8;stroke-width:0.265;stroke-opacity:1"
|
||||
x="79.537201"
|
||||
y="132.41594"
|
||||
id="tspan9589-7-1" /><tspan
|
||||
sodipodi:role="line"
|
||||
style="stroke:#2e7fc8;stroke-width:0.265;stroke-opacity:1"
|
||||
x="79.537201"
|
||||
y="135.94373"
|
||||
id="tspan9591-3-5" /><tspan
|
||||
sodipodi:role="line"
|
||||
style="stroke:#2e7fc8;stroke-width:0.265;stroke-opacity:1"
|
||||
x="79.537201"
|
||||
y="139.47151"
|
||||
id="tspan9593-6-5" /><tspan
|
||||
sodipodi:role="line"
|
||||
style="stroke:#2e7fc8;stroke-width:0.265;stroke-opacity:1"
|
||||
x="79.537201"
|
||||
y="142.9993"
|
||||
id="tspan9595-1-4" /><tspan
|
||||
sodipodi:role="line"
|
||||
style="stroke:#2e7fc8;stroke-width:0.265;stroke-opacity:1"
|
||||
x="79.537201"
|
||||
y="146.52708"
|
||||
id="tspan9597-2-7" /></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:3.175px;fill:#2e7fc8;fill-opacity:1;stroke-width:0.265;stroke-dasharray:none"
|
||||
x="51.876431"
|
||||
y="185.68427"
|
||||
id="text168-8-2-8-5-4"
|
||||
inkscape:highlight-color="#2e7fc8"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan166-97-7-7-0-7"
|
||||
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:14.1111px;font-family:Quicksand;-inkscape-font-specification:'Quicksand, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#2e7fc8;fill-opacity:1;stroke-width:0.265;stroke-dasharray:none"
|
||||
x="51.876431"
|
||||
y="185.68427"><tspan
|
||||
style="fill:#ffc332;fill-opacity:1"
|
||||
id="tspan11889-7-0-9-3-4">X</tspan></tspan></text>
|
||||
<path
|
||||
style="display:block;fill:none;stroke:#ffc332;stroke-width:0.890744;stroke-miterlimit:5;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect4212-5-8-1-2-6-4"
|
||||
width="29.109257"
|
||||
height="29.109257"
|
||||
x="40.844711"
|
||||
y="9.2966976"
|
||||
clip-path="url(#clipath_lpe_path-effect4223-1-4-9-0-9-9)"
|
||||
inkscape:path-effect="#path-effect4223-1-4-9-0-9-9"
|
||||
d="M 40.844711,9.2966976 H 69.953968 V 38.405954 H 40.844711 Z"
|
||||
sodipodi:type="rect"
|
||||
transform="translate(-18.779985,154.02602)" />
|
||||
<path
|
||||
style="display:block;fill:none;stroke:#ffc332;stroke-width:0.891;stroke-miterlimit:5;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect4221-8-3-0-1-3"
|
||||
width="29.109257"
|
||||
height="29.109257"
|
||||
x="45.057877"
|
||||
y="13.160081"
|
||||
clip-path="url(#clipath_lpe_path-effect4281-3-5-1-4-3)"
|
||||
inkscape:path-effect="#path-effect4281-3-5-1-4-5"
|
||||
d="M 45.057877,13.160081 H 74.167133 V 42.269338 H 45.057877 Z"
|
||||
sodipodi:type="rect"
|
||||
transform="translate(-17.918075,154.39216)"
|
||||
inkscape:export-filename="../36533220/favicon.png"
|
||||
inkscape:export-xdpi="105.58897"
|
||||
inkscape:export-ydpi="105.58897" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:2.82223px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';fill:#dedede;fill-opacity:0.704313;stroke-width:0.264999;stroke-miterlimit:5"
|
||||
x="80.231857"
|
||||
y="165.90228"
|
||||
id="text7650-2-0-0"><tspan
|
||||
sodipodi:role="line"
|
||||
style="stroke:#2e7fc8;stroke-width:0.265;stroke-opacity:1"
|
||||
x="80.231857"
|
||||
y="165.90228"
|
||||
id="tspan9579-9-6-7" /><tspan
|
||||
sodipodi:role="line"
|
||||
style="stroke:#fa6a31;stroke-width:0.265;stroke-opacity:1"
|
||||
x="80.231857"
|
||||
y="169.43007"
|
||||
id="tspan9581-2-3-8" /><tspan
|
||||
sodipodi:role="line"
|
||||
style="stroke:#ffc332;stroke-width:0.265;stroke-opacity:1"
|
||||
x="80.231857"
|
||||
y="172.95786"
|
||||
id="tspan9583-2-2-6">Avec un lien qui permet d'envoyer un message à tous les membres d'une nation </tspan><tspan
|
||||
sodipodi:role="line"
|
||||
style="stroke:#ffc332;stroke-width:0.265;stroke-opacity:1"
|
||||
x="80.231857"
|
||||
y="176.48564"
|
||||
id="tspan9585-8-0-8" /><tspan
|
||||
sodipodi:role="line"
|
||||
style="stroke:#ffc332;stroke-width:0.265;stroke-opacity:1"
|
||||
x="80.231857"
|
||||
y="180.01343"
|
||||
id="tspan9587-9-6-8">On garde le orange pour les towns</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
style="stroke:#2e7fc8;stroke-width:0.265;stroke-opacity:1"
|
||||
x="80.231857"
|
||||
y="183.54121"
|
||||
id="tspan9589-7-1-4" /><tspan
|
||||
sodipodi:role="line"
|
||||
style="stroke:#2e7fc8;stroke-width:0.265;stroke-opacity:1"
|
||||
x="80.231857"
|
||||
y="187.06902"
|
||||
id="tspan9591-3-5-3" /><tspan
|
||||
sodipodi:role="line"
|
||||
style="stroke:#2e7fc8;stroke-width:0.265;stroke-opacity:1"
|
||||
x="80.231857"
|
||||
y="190.5968"
|
||||
id="tspan9593-6-5-1" /><tspan
|
||||
sodipodi:role="line"
|
||||
style="stroke:#2e7fc8;stroke-width:0.265;stroke-opacity:1"
|
||||
x="80.231857"
|
||||
y="194.12459"
|
||||
id="tspan9595-1-4-4" /><tspan
|
||||
sodipodi:role="line"
|
||||
style="stroke:#2e7fc8;stroke-width:0.265;stroke-opacity:1"
|
||||
x="80.231857"
|
||||
y="197.65237"
|
||||
id="tspan9597-2-7-9" /></text>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 33 KiB |
1243
adminapi/www/cdn/chartegraphique/planchelogoapXtrib.svg
Normal file
After Width: | Height: | Size: 56 KiB |
BIN
adminapi/www/cdn/log/1x1.png
Normal file
After Width: | Height: | Size: 95 B |
1
adminapi/www/cdn/log/empty.json
Normal file
@ -0,0 +1 @@
|
||||
{}
|
76
adminapi/www/cdn/log/unique.svg
Normal file
@ -0,0 +1,76 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="10"
|
||||
height="10"
|
||||
viewBox="0 0 10 10"
|
||||
version="1.1"
|
||||
id="svg5"
|
||||
inkscape:version="1.1.2 (0a00cf5339, 2022-02-04)"
|
||||
sodipodi:docname="unique.svg"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview7"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:document-units="px"
|
||||
showgrid="false"
|
||||
width="359px"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0"
|
||||
inkscape:zoom="30.865211"
|
||||
inkscape:cx="-1.6847447"
|
||||
inkscape:cy="1.1177633"
|
||||
inkscape:window-width="3021"
|
||||
inkscape:window-height="1664"
|
||||
inkscape:window-x="1131"
|
||||
inkscape:window-y="27"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="layer1" />
|
||||
<defs
|
||||
id="defs2" />
|
||||
<g
|
||||
inkscape:label="Calque 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-129.59407,-246.35439)">
|
||||
<g
|
||||
id="g52036">
|
||||
<rect
|
||||
style="fill:#ffcc00"
|
||||
id="rect870"
|
||||
width="10"
|
||||
height="10"
|
||||
x="129.59407"
|
||||
y="246.35439" />
|
||||
<ellipse
|
||||
style="fill:#080000;fill-opacity:1;stroke-width:0.38616"
|
||||
id="path846"
|
||||
cx="134.72528"
|
||||
cy="250.50099"
|
||||
rx="1.3840007"
|
||||
ry="1.4566926" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-weight:normal;font-size:40px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke:none"
|
||||
x="132.92885"
|
||||
y="252.79332"
|
||||
id="text7558"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan7556"
|
||||
x="132.92885"
|
||||
y="252.79332"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:1.33333px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal">unique</tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.4 KiB |
@ -22,17 +22,17 @@ const checkHeaders = (req, res, next) => {
|
||||
* HTTP/1/1 400 Not Found
|
||||
* {
|
||||
* status:400,
|
||||
* ref:"headers"
|
||||
* ref:"middlewares"
|
||||
* msg:"missingheaders",
|
||||
* data: ["headermissing1"]
|
||||
* data: ["headermissing1"]
|
||||
* }
|
||||
*@apiErrorExample {json} Error-Response:
|
||||
* HTTP/1/1 404 Not Found
|
||||
* {
|
||||
* status:404,
|
||||
* ref:"headers"
|
||||
* ref:"middlewares"
|
||||
* msg:"tribeiddoesnotexist",
|
||||
* data: {xalias}
|
||||
* data: {xalias}
|
||||
* }
|
||||
*
|
||||
* @apiHeaderExample {json} Header-Exemple:
|
||||
@ -61,27 +61,28 @@ const checkHeaders = (req, res, next) => {
|
||||
missingheader.push(h);
|
||||
}
|
||||
}
|
||||
//console.log( 'header', header )
|
||||
// console.log( 'pass header', header )
|
||||
// store in session the header information
|
||||
req.session.header = header;
|
||||
// Each header have to be declared
|
||||
if (missingheader != "") {
|
||||
// bad request
|
||||
return res.status(400).json({
|
||||
ref: "headers",
|
||||
ref: "middlewares",
|
||||
msg: "missingheader",
|
||||
data: missingheader,
|
||||
});
|
||||
}
|
||||
//console.log( req.app.locals.tribeids )
|
||||
// xtribe == "town" is used during the setup process
|
||||
// xtribe == "adminapi" is used to access /adminapi
|
||||
if (
|
||||
!(
|
||||
header.xtribe == "town" || req.app.locals.tribeids.includes(header.xtribe)
|
||||
["town","adminapi"].includes(header.xtribe) || req.app.locals.tribeids.includes(header.xtribe)
|
||||
)
|
||||
) {
|
||||
return res.status(404).json({
|
||||
ref: "headers",
|
||||
ref: "middlewares",
|
||||
msg: "tribeiddoesnotexist",
|
||||
data: { xtribe: header.xtribe },
|
||||
});
|
||||
@ -90,6 +91,8 @@ const checkHeaders = (req, res, next) => {
|
||||
console.log("warning language requested does not exist force to english");
|
||||
header.xlang = "en";
|
||||
}
|
||||
//set anonymous profil
|
||||
req.session.header.xprofils=["anonymous"]
|
||||
next();
|
||||
};
|
||||
module.exports = checkHeaders;
|
||||
|
@ -1,69 +0,0 @@
|
||||
const fs = require("fs-extra");
|
||||
const glob = require("glob");
|
||||
const path = require("path");
|
||||
|
||||
const conf = require(`${process.env.dirtown}/conf.json`);
|
||||
|
||||
const hasAccessrighton = (object, action, ownby) => {
|
||||
/*
|
||||
@action (mandatory) : CRUDO
|
||||
@object (mandatory)= name of a folder object in /tribeid space can be a tree for example objects/items
|
||||
@ownby (option) = list des uuid propriétaire
|
||||
return next() if all action exist in req.app.local.tokens[UUID].ACCESSRIGHTS.data[object]
|
||||
OR if last action ="O" and uuid exist in ownBy
|
||||
Careffull if you have many action CRO let O at the end this will force req.right at true if the owner try an action on this object
|
||||
|
||||
need to check first a person exist with this alias in tribe
|
||||
|
||||
const person = fs.readJsonSync(
|
||||
`${conf.dirapi}/nationchains/tribes/${req.session.header.xtribe}/persons/${req.session.header.xalias}.json`
|
||||
);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
*/
|
||||
|
||||
return (req, res, next) => {
|
||||
//console.log( 'err.stack hasAccessrights', err.statck )
|
||||
//console.log( `test accessright on object:${object} for ${req.session.header.xworkon}:`, req.app.locals.tokens[ req.session.header.xpaganid ].ACCESSRIGHTS.data[ req.session.header.xworkon ] )
|
||||
req.right = false;
|
||||
if (
|
||||
req.app.locals.tokens[req.session.header.xpaganid].ACCESSRIGHTS.data[
|
||||
req.session.header.xworkon
|
||||
] &&
|
||||
req.app.locals.tokens[req.session.header.xpaganid].ACCESSRIGHTS.data[
|
||||
req.session.header.xworkon
|
||||
][object]
|
||||
) {
|
||||
req.right = true;
|
||||
[...action].forEach((a) => {
|
||||
if (a == "O" && ownby && ownby.includes(req.session.header.xpaganid)) {
|
||||
req.right = true;
|
||||
} else {
|
||||
req.right =
|
||||
req.right &&
|
||||
req.app.locals.tokens[
|
||||
req.session.header.xpaganid
|
||||
].ACCESSRIGHTS.data[req.session.header.xworkon][object].includes(a);
|
||||
}
|
||||
});
|
||||
}
|
||||
//console.log( 'Access data autorise? ', req.right )
|
||||
if (!req.right) {
|
||||
return res.status(403).json({
|
||||
info: "forbiddenAccessright",
|
||||
ref: "headers",
|
||||
moreinfo: {
|
||||
xpaganid: req.session.header.xpaganid,
|
||||
object: object,
|
||||
xworkon: req.session.header.xworkon,
|
||||
action: action,
|
||||
},
|
||||
});
|
||||
}
|
||||
next();
|
||||
};
|
||||
};
|
||||
module.exports = hasAccessrighton;
|
@ -1,118 +1,198 @@
|
||||
const fs = require("fs-extra");
|
||||
const dayjs = require("dayjs");
|
||||
const glob = require("glob");
|
||||
// To debug it could be easier with source code:
|
||||
// const openpgp = require("/media/phil/usbfarm/apxtrib/node_modules/openpgp/dist/node/openpgp.js");
|
||||
const openpgp = require("openpgp");
|
||||
|
||||
const conf = require(`${process.env.dirtown}/conf.json`);
|
||||
|
||||
/**
|
||||
* Check authentification and get person profils for a tribe
|
||||
* @param {object} req
|
||||
* @param {object} res
|
||||
* @param {function} next
|
||||
* @returns {status:}
|
||||
*
|
||||
* 3 steps:
|
||||
* - clean eventual tokens oldest than 24 hours (the first pagan that authenticate of the day will process this)
|
||||
* - if token present in /town/tmp/tokens/alias_tribe_part of the xhash return xprofils with list of profils pagans
|
||||
* - if no token then check xhash with openpgp lib and create one
|
||||
*
|
||||
* All data related are store in town/tmp/tokens backend, and localstorage headers for front end
|
||||
* A penalty function increase a sleep function between 2 fail try of authentification to avoid bruteforce
|
||||
*/
|
||||
const isAuthenticated = async (req, res, next) => {
|
||||
// tokens if valid are store in /dirtown/tmp/tokens/xalias_xdays_xhash(20,200)
|
||||
// tokens if valid are store in /dirtown/tmp/tokens/xalias_xdays_xhash(20,200)
|
||||
// once a day rm oldest tokens than 24hours tag job by adding tmp/tokensmenagedone{day}
|
||||
|
||||
const withlog = true;
|
||||
const currentday = dayjs().date();
|
||||
console.log(
|
||||
"if menagedone" + currentday,
|
||||
!fs.existsSync(`${process.env.dirtown}/tmp/tokensmenagedone${currentday}`)
|
||||
fs.ensureDirSync(`${process.env.dirtown}/tmp/tokens`);
|
||||
let menagedone = fs.existsSync(
|
||||
`${process.env.dirtown}/tmp/tokens/menagedone${currentday}`
|
||||
);
|
||||
if (!fs.existsSync(`${process.env.dirtown}/tmp/tokens`))
|
||||
fs.mkdirSync(`${process.env.dirtown}/tmp/tokens`);
|
||||
if (!fs.existsSync(`${process.env.dirtown}/tmp/tokensmenagedone${currentday}`)) {
|
||||
if (withlog)
|
||||
console.log(`menagedone${currentday} was it done today?:${menagedone}`);
|
||||
if (!menagedone) {
|
||||
// clean oldest
|
||||
const tsday = dayjs().valueOf(); // now in timestamp format
|
||||
glob.sync(`${process.env.dirtown}/tmp/tokensmenagedone*`).forEach((f) => {
|
||||
glob.sync(`${process.env.dirtown}/tmp/tokens/menagedone*`).forEach((f) => {
|
||||
fs.removeSync(f);
|
||||
});
|
||||
glob.sync(`${process.env.dirtown}/tmp/tokens/*.json`).forEach((f) => {
|
||||
if (tsday - parseInt(f.split("_")[1]) > 86400000) fs.remove(f);
|
||||
const fsplit = f.split("_");
|
||||
const elapse = tsday - parseInt(fsplit[2]);
|
||||
//24h 86400000 milliseconde 15mn 900000
|
||||
if (elapse && elapse > 86400000) {
|
||||
fs.remove(f);
|
||||
}
|
||||
});
|
||||
fs.outputFile(
|
||||
`${process.env.dirtown}/tmp/tokens/menagedone${currentday}`,
|
||||
"done by middleware/isAUthenticated"
|
||||
);
|
||||
}
|
||||
//Check register in tmp/tokens/
|
||||
console.log("isAuthenticate?");
|
||||
if (withlog) console.log("isAuthenticate?", req.session.header, req.body);
|
||||
|
||||
const resnotauth = {
|
||||
ref: "headers",
|
||||
ref: "middlewares",
|
||||
msg: "notauthenticated",
|
||||
data: {
|
||||
xalias: req.session.header.xalias,
|
||||
xaliasexists: true,
|
||||
},
|
||||
};
|
||||
//console.log(req.session.header);
|
||||
if (req.session.header.xalias == "anonymous" || req.session.header.xhash == "anonymous") {
|
||||
console.log("alias anonymous means not auth");
|
||||
return res.status(401).json(resnotauth);
|
||||
if (
|
||||
req.session.header.xalias == "anonymous" ||
|
||||
req.session.header.xhash == "anonymous"
|
||||
) {
|
||||
if (withlog) console.log("alias anonymous means not auth");
|
||||
resnotauth.status = 401;
|
||||
return res.status(resnotauth.status).json(resnotauth);
|
||||
}
|
||||
|
||||
const tmpfs = `${process.env.dirtown}/tmp/tokens/${req.session.header.xalias}_${
|
||||
req.session.header.xdays
|
||||
}_${req.session.header.xhash.substring(20, 200)}`;
|
||||
//console.log(tmpfs);
|
||||
let tmpfs = `${process.env.dirtown}/tmp/tokens/${req.session.header.xalias}_${req.session.header.xtribe}_${req.session.header.xdays}`;
|
||||
//max filename in ext4: 255 characters
|
||||
tmpfs += `_${req.session.header.xhash.substring(
|
||||
150,
|
||||
150 + tmpfs.length - 249
|
||||
)}.json`;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} alias that request an access
|
||||
* @param {string} action "clean" | "penalty"
|
||||
*/
|
||||
const bruteforcepenalty = async (alias, action) => {
|
||||
const sleep = (ms) => {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
};
|
||||
const failstamp = `${process.env.dirtown}/tmp/tokens/${alias}.json`;
|
||||
if (action == "clean") {
|
||||
//to reinit bruteforce checker
|
||||
if (withlog) console.log("try to clean penalty file ", failstamp);
|
||||
fs.remove(failstamp, (err) => {
|
||||
if (err) console.log("Check forcebrut ", err);
|
||||
});
|
||||
} else if (action == "penalty") {
|
||||
const stamp = fs.existsSync(failstamp)
|
||||
? fs.readJSONSync(failstamp)
|
||||
: { lastfail: dayjs().format(), numberfail: 0 };
|
||||
stamp.lastfail = dayjs().format();
|
||||
stamp.numberfail += 1;
|
||||
fs.outputJSON(failstamp, stamp);
|
||||
if (withlog) console.log("penalty:", stamp);
|
||||
await sleep(stamp.numberfail * 100); //increase of 0,1 second the answer time per fail
|
||||
if (withlog) console.log("time out penalty");
|
||||
}
|
||||
};
|
||||
if (!fs.existsSync(tmpfs)) {
|
||||
// need to check detached sign
|
||||
let publickey;
|
||||
if (
|
||||
fs.existsSync(
|
||||
`${conf.dirapi}/nationchains/pagans/itm/${req.session.header.xalias}.json`
|
||||
)
|
||||
) {
|
||||
const pagan = fs.readJsonSync(
|
||||
`${conf.dirapi}/nationchains/pagans/itm/${req.session.header.xalias}.json`
|
||||
);
|
||||
publickey = pagan.publicKey;
|
||||
} else {
|
||||
let publickey = "";
|
||||
console.log(process.cwd());
|
||||
console.log(process.env.PWD);
|
||||
console.log(__dirname);
|
||||
const aliasinfo = `${process.env.PWD}/nationchains/pagans/itm/${req.session.header.xalias}.json`;
|
||||
if (fs.existsSync(aliasinfo)) {
|
||||
publickey = fs.readJsonSync(aliasinfo).publickey;
|
||||
} else if (req.body.publickey) {
|
||||
resnotauth.data.xaliasexists = false;
|
||||
if (req.body.publickey) {
|
||||
publickey = req.body.publickey;
|
||||
} else {
|
||||
console.log("alias unknown");
|
||||
return res.status(404).send(resnotauth);
|
||||
publickey = req.body.publickey;
|
||||
}
|
||||
if (publickey == "") {
|
||||
if (withlog) console.log("alias unknown");
|
||||
resnotauth.status = 404;
|
||||
resnotauth.data.xaliasexists = false;
|
||||
return res.status(resnotauth.status).send(resnotauth);
|
||||
}
|
||||
if (withlog) console.log("publickey", publickey);
|
||||
if (publickey.substring(0, 31) !== "-----BEGIN PGP PUBLIC KEY BLOCK") {
|
||||
if (withlog)
|
||||
console.log("Publickey is not valid as armored key:", publickey);
|
||||
await bruteforcepenalty(req.session.header.xalias, "penalty");
|
||||
resnotauth.status = 404;
|
||||
return res.status(resnotauth.status).send(resnotauth);
|
||||
}
|
||||
const clearmsg = Buffer.from(req.session.header.xhash, "base64").toString();
|
||||
if (clearmsg.substring(0, 10) !== "-----BEGIN") {
|
||||
if (withlog)
|
||||
console.log("xhash conv is not valid as armored key:", clearmsg);
|
||||
await bruteforcepenalty(req.session.header.xalias, "penalty");
|
||||
resnotauth.status = 404;
|
||||
return res.status(resnotauth.status).send(resnotauth);
|
||||
}
|
||||
if (withlog) console.log("clearmsg", clearmsg);
|
||||
const pubkey = await openpgp.readKey({ armoredKey: publickey });
|
||||
const signedMessage = await openpgp.readCleartextMessage({
|
||||
cleartextMessage: clearmsg,
|
||||
});
|
||||
const verificationResult = await openpgp.verify({
|
||||
message: signedMessage,
|
||||
verificationKeys: pubkey,
|
||||
});
|
||||
if (withlog) console.log(verificationResult);
|
||||
if (withlog) console.log(verificationResult.signatures[0].keyID.toHex());
|
||||
try {
|
||||
await verificationResult.signatures[0].verified;
|
||||
if (
|
||||
verificationResult.data !=
|
||||
`${req.session.header.xalias}_${req.session.header.xdays}`
|
||||
) {
|
||||
resnotauth.msg = "signaturefailled";
|
||||
if (withlog)
|
||||
console.log(
|
||||
`message recu:${verificationResult.data} , message attendu:${req.session.header.xalias}_${req.session.header.xdays}`
|
||||
);
|
||||
await bruteforcepenalty(req.session.header.xalias, "penalty");
|
||||
resnotauth.status = 401;
|
||||
return res.status(resnotauth.status).send(resnotauth);
|
||||
}
|
||||
}
|
||||
if (publickey.substring(0,10)!=="-----BEGIN"){
|
||||
console.log("Publickey is not valid as armored key:", publickey)
|
||||
return res.status(404).send(resnotauth);
|
||||
}
|
||||
if (Buffer.from(req.session.header.xhash, "base64").toString().substring(0,10)!=="-----BEGIN"){
|
||||
console.log("xhash conv is not valid as armored key:", Buffer.from(req.session.header.xhash, "base64").toString())
|
||||
return res.status(404).send(resnotauth);
|
||||
}
|
||||
let publicKey;
|
||||
try {
|
||||
publicKey = await openpgp.readKey({ armoredKey: publickey });
|
||||
}catch(err){
|
||||
console.log(erreur)
|
||||
}
|
||||
const msg = await openpgp.createMessage({
|
||||
text: `${req.session.header.xalias}_${req.session.header.xdays}`,
|
||||
});
|
||||
const signature = await openpgp.readSignature({
|
||||
armoredSignature: Buffer.from(
|
||||
req.session.header.xhash,
|
||||
"base64"
|
||||
).toString(),
|
||||
});
|
||||
//console.log(msg);
|
||||
//console.log(signature);
|
||||
//console.log(publicKey);
|
||||
const checkauth = await openpgp.verify({
|
||||
message: msg,
|
||||
signature: signature,
|
||||
verificationKeys: publicKey,
|
||||
});
|
||||
//console.log(checkauth);
|
||||
//console.log(checkauth.signatures[0].keyID);
|
||||
//console.log(await checkauth.signatures[0].signature);
|
||||
//console.log(await checkauth.signatures[0].verified);
|
||||
|
||||
const { check, keyID } = checkauth.signatures[0];
|
||||
try {
|
||||
await check; // raise an error if necessary
|
||||
fs.outputFileSync(tmpfs, req.session.header.xhash, "utf8");
|
||||
} catch (e) {
|
||||
resnotauth.msg = "signaturefailed";
|
||||
console.log("not auth fail sign");
|
||||
return res.status(401).send(resnotauth);
|
||||
resnotauth.msg = "signaturefailled";
|
||||
if (withlog) console.log("erreur", e);
|
||||
await bruteforcepenalty(req.session.header.xalias, "penalty");
|
||||
resnotauth.status = 401;
|
||||
return res.status(resnotauth.status).send(resnotauth);
|
||||
}
|
||||
// authenticated then get person profils (person = pagan for a xtrib)
|
||||
req.session.header.xprofils.push("pagans");
|
||||
const person = `${process.env.dirtown}/tribes/${req.session.header.xtribe}/persons/itm/${req.session.header.xalias}.json`;
|
||||
if (withlog) {
|
||||
console.log("Profils tribe/app management");
|
||||
console.log("person", person);
|
||||
}
|
||||
if (fs.existsSync(person)) {
|
||||
const infoperson = fs.readJSONSync(person);
|
||||
console.log(infoperson);
|
||||
infoperson.profils.forEach((p) => req.session.header.xprofils.push(p));
|
||||
}
|
||||
fs.outputJSONSync(tmpfs, req.session.header.xprofils);
|
||||
} else {
|
||||
//tmpfs exist get profils from identification process
|
||||
req.session.header.xprofils = fs.readJSONSync(tmpfs);
|
||||
}
|
||||
console.log("Authenticated");
|
||||
bruteforcepenalty(req.session.header.xalias, "clean");
|
||||
console.log(`${req.session.header.xalias} Authenticated`);
|
||||
next();
|
||||
};
|
||||
module.exports = isAuthenticated;
|
||||
|
@ -11,7 +11,7 @@ Checkjson.schema = {};
|
||||
Checkjson.schema.properties = {};
|
||||
Checkjson.schema.properties.type = {};
|
||||
Checkjson.schema.properties.type.string = (str) => typeof str === "string";
|
||||
Checkjson.schema.properties.type.array = (val)=> Array.isArray(val);
|
||||
Checkjson.schema.properties.type.array = (val) => Array.isArray(val);
|
||||
Checkjson.schema.properties.type.number = (n) => typeof n === "number";
|
||||
Checkjson.schema.properties.type.boolean = (n) => typeof n === "boolean";
|
||||
Checkjson.schema.properties.type.integer = (n) =>
|
||||
@ -47,19 +47,44 @@ Checkjson.schema.properties.range = (
|
||||
};
|
||||
Checkjson.schema.properties.pattern = (str, pattern) => {
|
||||
try {
|
||||
pattern= new RegExp(pattern);
|
||||
pattern = new RegExp(pattern);
|
||||
} catch (e) {
|
||||
console.log('err pattern in checkjon',pattern);
|
||||
console.log("err pattern in checkjon", pattern);
|
||||
return false;
|
||||
}
|
||||
return pattern.test(str);
|
||||
};
|
||||
Checkjson.schema.properties.enum = (str, enumvalues) =>
|
||||
typeof str === "string" && enumvalues.includes(str);
|
||||
Checkjson.schema.properties.enum = (str, enumvalues) => {
|
||||
if (Array.isArray(enumvalues)) {
|
||||
return typeof str === "string" && enumvalues.includes(str);
|
||||
} else if (tribeId) {
|
||||
//enumvalues is a reference of objectname.key
|
||||
const { tribeId, obj, keyid } = enumvalues.split(".");
|
||||
return fs.existsSync(
|
||||
`${conf.dirtown}/tribes/${tribeId}/schema/${obj}/itm/${keyid}.json`
|
||||
);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
// to check a value for a pattern
|
||||
// Checkjson.schema.properties.pattern(value, properties[p].pattern)
|
||||
/**
|
||||
*
|
||||
* @param {string} str to test
|
||||
* @param {string} format keyworkd existing in Checkjson.schema.properties.format
|
||||
* @return null if format does not exist, true or false
|
||||
*/
|
||||
Checkjson.testformat=(str, format)=>{
|
||||
if (!Checkjson.schema.properties.format[format]) { return null}
|
||||
return Checkjson.schema.properties.pattern(str, Checkjson.schema.properties.format[format])
|
||||
|
||||
}
|
||||
// see format https://json-schema.org/understanding-json-schema/reference/string.html#format
|
||||
// to check a just value with a format use Checkjson.testformat=(value, format)
|
||||
Checkjson.schema.properties.format = {
|
||||
"date-time": /\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d{1,3}/,
|
||||
stringalphaonly:/^[A-Za-z0-9]{3,}$/,
|
||||
stringalphaonly: /^[A-Za-z0-9]{3,}$/,
|
||||
time: /[0-2]\d:[0-5]\d:[0-5]\d\.\d{1,3}/,
|
||||
date: /\d{4}-[01]\d-[0-3]\d/,
|
||||
duration: / /,
|
||||
@ -79,11 +104,16 @@ Checkjson.schema.properties.format = {
|
||||
password:
|
||||
/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[$@$!%*?&.])[A-Za-z\d$@$!%*?&.{}:|\s]{8,}/,
|
||||
postalcodefr: /(^\d{5}$)|(^\d{5}-\d{4}$)/,
|
||||
pgppublickey:
|
||||
/^-----BEGIN PGP PUBLIC KEY BLOCK-----(\n|\r|\r\n)(\n|\r|\r\n)([0-9a-zA-Z\+\/=]*(\n|\r|\r\n))*-----END PGP PUBLIC KEY BLOCK-----(\n|\r|\r\n)?$/gm,
|
||||
pgpprivatekey:
|
||||
/^-----BEGIN PGP PRIVATE KEY BLOCK-----(\n|\r|\r\n)(\n|\r|\r\n)([0-9a-zA-Z\+\/=]*(\n|\r|\r\n))*-----END PGP PRIVATE KEY BLOCK-----(\n|\r|\r\n)?$/gm,
|
||||
};
|
||||
Checkjson.schema.properties.default
|
||||
Checkjson.schema.properties.default;
|
||||
Checkjson.schema.validation = (schema) => {
|
||||
/*validate a schema structure*/
|
||||
const res = { status: 200, err: [] };
|
||||
const multimsg = [];
|
||||
const res = {};
|
||||
if (schema.properties) {
|
||||
Object.keys(schema.properties).forEach((p) => {
|
||||
const properties = schema.properties;
|
||||
@ -92,10 +122,10 @@ Checkjson.schema.validation = (schema) => {
|
||||
typeof properties[p].type === "string" &&
|
||||
!Checkjson.schema.properties.type[properties[p].type]
|
||||
) {
|
||||
res.err.push({
|
||||
ref:"Checkjson",
|
||||
msg:"schemaerrtypedoesnotexist",
|
||||
data: {propertie:p,type:properties[p].type}
|
||||
multimsg.push({
|
||||
ref: "Checkjson",
|
||||
msg: "schemaerrtypedoesnotexist",
|
||||
data: { propertie: p, type: properties[p].type },
|
||||
});
|
||||
}
|
||||
if (
|
||||
@ -105,10 +135,10 @@ Checkjson.schema.validation = (schema) => {
|
||||
) {
|
||||
properties[p].type.forEach((tp) => {
|
||||
if (!Checkjson.schema.properties.type[tp])
|
||||
res.err.push({
|
||||
ref:"Checkjson",
|
||||
msg:"schemaerrtypedoesnotexist",
|
||||
data: {propertie:p,type:properties[p].type}
|
||||
multimsg.push({
|
||||
ref: "Checkjson",
|
||||
msg: "schemaerrtypedoesnotexist",
|
||||
data: { propertie: p, type: properties[p].type },
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -116,26 +146,41 @@ Checkjson.schema.validation = (schema) => {
|
||||
properties[p].format &&
|
||||
!Checkjson.schema.properties.format[properties[p].format]
|
||||
) {
|
||||
res.err.push({
|
||||
ref:"Checkjson",
|
||||
msg:"schemaerrformatdoesnotexist",
|
||||
data: {propertie:p,format:properties[p].format}
|
||||
multimsg.push({
|
||||
ref: "Checkjson",
|
||||
msg: "schemaerrformatdoesnotexist",
|
||||
data: { propertie: p, format: properties[p].format },
|
||||
});
|
||||
}
|
||||
if (properties[p].enum && !Array.isArray(properties[p].enum)) {
|
||||
res.err.push({
|
||||
ref:"Checkjson",
|
||||
msg:"schemaerrenumnotarray",
|
||||
data: {propertie:p,enum:properties[p].enum}
|
||||
multimsg.push({
|
||||
ref: "Checkjson",
|
||||
msg: "schemaerrenumnotarray",
|
||||
data: { propertie: p, enum: properties[p].enum },
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
// 406 means not acceptable
|
||||
if (res.err.length > 0) res.status = 406;
|
||||
if (multimsg.length > 0) {
|
||||
res.status = 406;
|
||||
res.multimsg = multimsg;
|
||||
} else {
|
||||
res.status = 200;
|
||||
res.ref = "Checkjson";
|
||||
res.msg = "validcheck";
|
||||
}
|
||||
return res;
|
||||
};
|
||||
|
||||
/**
|
||||
* Check data with a schema
|
||||
*
|
||||
* @param {object} schema a json schema
|
||||
* @param {*} data some data to check using schema
|
||||
* @param {*} withschemacheck boolean that force a schema check (usefull on modification schema)
|
||||
* @returns {status: 200, ref:"Checkjson", msg:"validcheck", data:{itm:object}}
|
||||
* {status:417, multimsg:[{re,msg,data}],data:{itm:object}}
|
||||
*/
|
||||
Checkjson.schema.data = (schema, data, withschemacheck) => {
|
||||
/* validate a data set with a schema in a context ctx */
|
||||
/*
|
||||
@ -148,7 +193,11 @@ Checkjson.schema.data = (schema, data, withschemacheck) => {
|
||||
const validschema = Checkjson.schema.validation(schema);
|
||||
if (validschema.status != 200) return validschema;
|
||||
}
|
||||
const res = { status: 200, err: [] };
|
||||
const multimsg = [];
|
||||
const res = {
|
||||
status: 200,
|
||||
data: { itm: data },
|
||||
};
|
||||
if (schema.properties) {
|
||||
const properties = schema.properties;
|
||||
Object.keys(properties).forEach((p) => {
|
||||
@ -164,40 +213,61 @@ Checkjson.schema.data = (schema, data, withschemacheck) => {
|
||||
if (Checkjson.schema.properties.type[typ](data[p])) valid = true;
|
||||
});
|
||||
if (!valid)
|
||||
res.err.push({
|
||||
ref:"Checkjson",
|
||||
msg:"dataerrpropertie",
|
||||
data: {key:p,value:data[p]}
|
||||
multimsg.push({
|
||||
ref: "Checkjson",
|
||||
msg: "dataerrpropertie",
|
||||
data: { key: p, value: data[p] },
|
||||
});
|
||||
|
||||
if (
|
||||
properties[p].minLength &&
|
||||
!Checkjson.schema.properties.minLength(data[p], properties[p].minLength)
|
||||
!Checkjson.schema.properties.minLength(
|
||||
data[p],
|
||||
properties[p].minLength
|
||||
)
|
||||
) {
|
||||
res.err.push({
|
||||
ref:"Checkjson",
|
||||
msg:"dataerrpropertie",
|
||||
data:{key:p,value:data[p],minLength:properties[p].minLength}
|
||||
});
|
||||
multimsg.push({
|
||||
ref: "Checkjson",
|
||||
msg: "dataerrpropertie",
|
||||
data: {
|
||||
key: p,
|
||||
value: data[p],
|
||||
minLength: properties[p].minLength,
|
||||
},
|
||||
});
|
||||
}
|
||||
if (
|
||||
properties[p].maxLength &&
|
||||
!Checkjson.schema.properties.maxLength(data[p], properties[p].maxLength)
|
||||
!Checkjson.schema.properties.maxLength(
|
||||
data[p],
|
||||
properties[p].maxLength
|
||||
)
|
||||
) {
|
||||
res.err.push({
|
||||
ref:"Checkjson",
|
||||
msg:"dataerrpropertie",
|
||||
data:{key:p,value:data[p],maxLength:properties[p].maxLength}
|
||||
multimsg.push({
|
||||
ref: "Checkjson",
|
||||
msg: "dataerrpropertie",
|
||||
data: {
|
||||
key: p,
|
||||
value: data[p],
|
||||
maxLength: properties[p].maxLength,
|
||||
},
|
||||
});
|
||||
}
|
||||
if (
|
||||
properties[p].multipleOf &&
|
||||
!Checkjson.schema.properties.multipleOf(data[p], properties[p].multipleOf)
|
||||
!Checkjson.schema.properties.multipleOf(
|
||||
data[p],
|
||||
properties[p].multipleOf
|
||||
)
|
||||
) {
|
||||
res.err.push({
|
||||
ref:"Checkjson",
|
||||
msg:"dataerrpropertie",
|
||||
data:{key:p,value:data[p],multipleOf:properties[p].multipleOf}
|
||||
multimsg.push({
|
||||
ref: "Checkjson",
|
||||
msg: "dataerrpropertie",
|
||||
data: {
|
||||
key: p,
|
||||
value: data[p],
|
||||
multipleOf: properties[p].multipleOf,
|
||||
},
|
||||
});
|
||||
}
|
||||
if (
|
||||
@ -216,10 +286,17 @@ Checkjson.schema.data = (schema, data, withschemacheck) => {
|
||||
properties[p].exclusiveMaximum
|
||||
)
|
||||
) {
|
||||
res.err.push({
|
||||
ref:"Checkjson",
|
||||
msg:"dataerrpropertie",
|
||||
data:{key:p,value:data[p],minimum:properties[p].minimum,maximum:properties[p].maximum,exclusiveMinimum:properties[p].exclusiveMinimum,exclusiveMaximum:properties[p].exclusiveMaximum}
|
||||
multimsg.push({
|
||||
ref: "Checkjson",
|
||||
msg: "dataerrpropertie",
|
||||
data: {
|
||||
key: p,
|
||||
value: data[p],
|
||||
minimum: properties[p].minimum,
|
||||
maximum: properties[p].maximum,
|
||||
exclusiveMinimum: properties[p].exclusiveMinimum,
|
||||
exclusiveMaximum: properties[p].exclusiveMaximum,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -227,10 +304,10 @@ Checkjson.schema.data = (schema, data, withschemacheck) => {
|
||||
properties[p].enum &&
|
||||
!Checkjson.schema.properties.enum(data[p], properties[p].enum)
|
||||
) {
|
||||
res.err.push({
|
||||
ref:"Checkjson",
|
||||
msg:"dataerrpropertie",
|
||||
data:{key:p,value:data[p],enumlst:properties[p].enum}
|
||||
multimsg.push({
|
||||
ref: "Checkjson",
|
||||
msg: "dataerrpropertie",
|
||||
data: { key: p, value: data[p], enumlst: properties[p].enum },
|
||||
});
|
||||
}
|
||||
if (properties[p].format) {
|
||||
@ -241,22 +318,32 @@ Checkjson.schema.data = (schema, data, withschemacheck) => {
|
||||
properties[p].pattern &&
|
||||
!Checkjson.schema.properties.pattern(data[p], properties[p].pattern)
|
||||
) {
|
||||
res.err.push({
|
||||
ref:"Checkjson",
|
||||
msg:"dataerrpropertie",
|
||||
data:{key:p,value:data[p],pattern:properties[p].pattern}
|
||||
multimsg.push({
|
||||
ref: "Checkjson",
|
||||
msg: "dataerrpropertie",
|
||||
data: { key: p, value: data[p], pattern: properties[p].pattern },
|
||||
});
|
||||
}
|
||||
} else if (schema.required && schema.required.includes(p)) {
|
||||
res.err.push({
|
||||
ref:"Checkjson",
|
||||
msg:"dataerrpropertierequired",
|
||||
data:{key:p,required:true}
|
||||
multimsg.push({
|
||||
ref: "Checkjson",
|
||||
msg: "dataerrpropertierequired",
|
||||
data: { key: p, required: true },
|
||||
});
|
||||
}
|
||||
});
|
||||
} //end properties
|
||||
if (schema.apxid) {
|
||||
res.data.apxid = data[schema.apxid];
|
||||
}
|
||||
if (multimsg.length > 0) {
|
||||
res.status = 417;
|
||||
res.multimsg = multimsg;
|
||||
} else {
|
||||
res.status = 200;
|
||||
res.ref = "Checkjson";
|
||||
res.msg = "validcheck";
|
||||
}
|
||||
if (res.err.length > 0) res.status = 417;
|
||||
return res;
|
||||
};
|
||||
if (typeof module !== "undefined") module.exports = Checkjson;
|
||||
|
@ -1,7 +1,10 @@
|
||||
const glob = require("glob");
|
||||
const path = require("path");
|
||||
const fs = require("fs-extra");
|
||||
|
||||
const axios = require("axios");
|
||||
//const smtp = require("smtp-client");
|
||||
const nodemailer = require("nodemailer");
|
||||
const conf = require(`${process.env.dirtown}/conf.json`);
|
||||
/**
|
||||
* To manage any communication between Pagan
|
||||
* mayor druid emailing/sms/paper from tribe register smtp, simcard, mail api to Person(s) / Pagan(s)
|
||||
@ -11,10 +14,160 @@ const fs = require("fs-extra");
|
||||
|
||||
const Notifications = {};
|
||||
|
||||
Notifications.send = (data) => {
|
||||
const ret = {};
|
||||
console.log("TODO dev notification emailing");
|
||||
return ret;
|
||||
|
||||
Notifications.sendsms = async (data, tribeId) => {
|
||||
/**
|
||||
* Never use need wallet in mailjet to test
|
||||
* To set up with mailjet see https://dev.mailjet.com/sms/guides/send-sms-api/#authentication
|
||||
*
|
||||
* @param {string} data.To a phone number with international +3360101010101
|
||||
* @param {string} data.Text text to send
|
||||
*
|
||||
* a conf.sms with {url:"smsurl", Token:"", From:""}
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
if (!conf.sms) {
|
||||
return {
|
||||
status: 412,
|
||||
ref: "Notifications",
|
||||
msg: "missingconf",
|
||||
tribe: tribeId,
|
||||
};
|
||||
}
|
||||
let missingk = [][("To", "Text")].forEach((k) => {
|
||||
if (!data[k]) {
|
||||
missingk.push(k);
|
||||
}
|
||||
});
|
||||
if (missingk.lenght > 0) {
|
||||
return {
|
||||
status: 428,
|
||||
ref: "Notifications",
|
||||
msg: "missingdata",
|
||||
missingk: missingk,
|
||||
};
|
||||
}
|
||||
let confsms= conf.sms;
|
||||
if (
|
||||
fs.existsSync(
|
||||
`${process.env.dirtown}/tribes/itm/${req.session.header.xtribe}.json`
|
||||
)
|
||||
) {
|
||||
const conftrib = fs.readJSONSync(
|
||||
`${process.env.dirtown}/tribes/itm/${req.session.header.xtribe}.json`
|
||||
);
|
||||
if (conftrib.sms) confsms = conftrib.sms;
|
||||
}
|
||||
data.From=confsms.From
|
||||
const sendsms= await axios.post(confsms.url,
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${confsms.MJ_TOKEN}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
if (sendsms.status==200){
|
||||
return {status:200,ref:"Notifications",msg:"successfullsentsms"};
|
||||
}else{
|
||||
return {status:sendsms.status, ref:"Notifications",msg:"errsendsms",err:sendsms.data}
|
||||
}
|
||||
|
||||
/* si tout se passe bien:
|
||||
{
|
||||
"From": "MJPilot",
|
||||
"To": "+33600000000",
|
||||
"Text": "Have a nice SMS flight with Mailjet !",
|
||||
"MessageId": "2034075536371630429",
|
||||
"SmsCount": 1,
|
||||
"CreationTS": 1521626400,
|
||||
"SentTS": 1521626402,
|
||||
"Cost": {
|
||||
"Value": 0.0012,
|
||||
"Currency": "EUR"
|
||||
},
|
||||
"Status": {
|
||||
"Code": 2,
|
||||
"Name": "sent",
|
||||
"Description": "Message sent"
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
};
|
||||
|
||||
Notifications.sendmail = async (data, tribe) => {
|
||||
/**
|
||||
* @param {string} data.From an email authorized by smtp used priority from header xtribe
|
||||
* @param {string} data.To list of email separate by ,
|
||||
* @param {string} data.subject
|
||||
* @param {string} data.html
|
||||
* @param {string} data.text
|
||||
* @param {string} data.Cc list of email in copy
|
||||
* @param {string} data.Bcc list of email in hidden copy
|
||||
* @param {string} data.filelist an array of object {filename:"",pathfile:"",filetype:""} pathfile to attach as file name of type:filetype "filename" to this email
|
||||
* example of filetype : "text/plain", "text/csv", image/gif", "application/json", "application/zip"
|
||||
*
|
||||
* @example data
|
||||
* {"From":"wall-ants.ndda.fr",
|
||||
* "To":"wall-ants.ndda.fr",
|
||||
* "subject":"Test",
|
||||
* "html":"<h1>test welcome</h1>",
|
||||
* "text":"test welcome",
|
||||
* "attachments":[{filename:"text.txt",pathfile:"/media/phil/textA.txt","contenttype":"text/plain"}]
|
||||
* }
|
||||
* @return {object} { status: 200, ref:"pagans",msg:"aliasexist",data: { alias, publicKey } }
|
||||
*
|
||||
*
|
||||
*/
|
||||
if (!conf.smtp) {
|
||||
return {
|
||||
status: 412,
|
||||
ref: "Notifications",
|
||||
msg: "missingconf",
|
||||
tribe: tribeId,
|
||||
};
|
||||
}
|
||||
let missingk = [];
|
||||
["from", "to", "subject", "html", "text"].forEach((k) => {
|
||||
if (!data[k]) {
|
||||
missingk.push(k);
|
||||
}
|
||||
});
|
||||
if (missingk.lenght > 0) {
|
||||
return {
|
||||
status: 428,
|
||||
ref: "Notifications",
|
||||
msg: "missingdata",
|
||||
missingk: missingk,
|
||||
};
|
||||
}
|
||||
const conftribfile=`${process.env.dirtown}/tribes/itm/${tribe}.json`;
|
||||
const confsmtp =(fs.existsSync(conftribfile))? fs.readJSONSync(conftribfile).smtp : conf.smtp;
|
||||
|
||||
//const client = smtp.connect(confsmtp);
|
||||
const transporter = await nodemailer.createTransport(confsmtp);
|
||||
//@todo add attachments management
|
||||
let missingfile=[]
|
||||
if (missingfile.lenght > 0)
|
||||
return {
|
||||
status: 428,
|
||||
ref: "Notifications",
|
||||
msg: "missingfile",
|
||||
missingfile: missingfile,
|
||||
};
|
||||
try {
|
||||
// Send the email
|
||||
//const res = await client.sendMail(data)
|
||||
const res = await transporter.sendMail(data)
|
||||
//console.log('res envoie',res)
|
||||
return { status: 200, ref: "Notifications", msg: "successfullsent", data };
|
||||
} catch (err) {
|
||||
//console.log('err envoie',err)
|
||||
return { status: 502, ref: "Notifications", msg: "errsendmail", err: err };
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = Notifications;
|
||||
|
@ -6,40 +6,85 @@ const axios = require("axios");
|
||||
const conf = require(`${process.env.dirtown}/conf.json`);
|
||||
const Checkjson = require(`./Checkjson.js`);
|
||||
|
||||
/* This manage Objects for indexing and check and act to CRUD
|
||||
objectpath/objects/schema/objectName.json
|
||||
/objectNames/searchindes/objectName_valueofkey_uuildlist.json
|
||||
/objectNames/uuid.json
|
||||
/**
|
||||
* This manage Objects for indexing, searching, checking and act to CRUD
|
||||
* @objectPathName = objectpath/objectname
|
||||
* objectpath/objectname/conf.json
|
||||
* /idx/all_key1.json = {key1value:{object}}
|
||||
* lst_key1.json = [key1valA,key1val2,...]
|
||||
* key2_key1.json = {key2value:[key1value]}
|
||||
* all_key1_filtername = {key1value:{object}}
|
||||
* /itm/apxidvalue.json
|
||||
* in conf.json:
|
||||
* {
|
||||
* "name": "object name ex:'nations'",
|
||||
* "schema": "relativ schema from dirapi dirtown ex:'adminapi/schema/nations.json'"",
|
||||
* "lastupdateschema": 0, time stamp last schema update
|
||||
* "lastupdatedata":0 time stamp last itm update
|
||||
* }
|
||||
*
|
||||
* Specifics key in schema to apXtrib:
|
||||
* apxid : the field value to use to store item
|
||||
* apxuniquekey : list of field that has to be unique you cannot have 2 itm with same key value
|
||||
* apxidx : list of index file /idx/
|
||||
* { "name":"lst_fieldA", "keyval": "alias" }, => lst_fieldA.json = [fieldAvalue1,...]
|
||||
{ "name":"all_fieldA", "keyval": "fieldA" }, => all_fieldA.json =
|
||||
if fieldA in apxuniquekey = {fieldAvalue1:{object}}
|
||||
not in apxuniquekey = {fieldAvalue1:[{object}]}
|
||||
{ "name":"word_fieldA", "keyval": "fieldA", "objkey": ["fieldB"]}, => word_fieldA.json
|
||||
if fieldA in apxuniquekey = {fieldAvalue1:fieldBvalue,}
|
||||
if fieldA not in uniquekey = {fieldAvalue1: [fieldBv1,fieldBv2,]}
|
||||
{ "name":"word_fieldA", "keyval": "fieldA", "objkey": ["fieldB","fieldC"]}, => word_fieldA.json
|
||||
if fieldA in apxuniquekey = {fieldAvalue1:{fieldB:val,fieldC:val},}
|
||||
if fieldA not in uniquekey = {fieldAvalue1: [{fieldB:val,fieldC:val},]}
|
||||
* apxaccessrights : list of profil with CRUD accesrights
|
||||
|
||||
|
||||
|
||||
**/
|
||||
|
||||
*/
|
||||
const Odmdb = {};
|
||||
/*
|
||||
Input: metaobject => data mapper of Key: Value
|
||||
|
||||
objname + an object {} + action Checkjson => get a valid or not answer
|
||||
objname + an object {} + action search => apply matching algo to find probalistic object id
|
||||
objname + action index => update /searcindex of objects concern
|
||||
/**
|
||||
* @api syncObject
|
||||
* @param {string} url to an existing object conf (/objectname/conf.json)
|
||||
* @param {timestamp} timestamp
|
||||
* 0 => rebuild local object from all_{idapx}.json
|
||||
* >0 => update itm and idx search by datetime
|
||||
* @param
|
||||
*/
|
||||
Odmdb.syncObject = () => {};
|
||||
|
||||
*/
|
||||
|
||||
Odmdb.setObject = (schemaPath, objectPath, objectName, schema, lgjson, lg) => {
|
||||
/**
|
||||
*
|
||||
* @schemapath {string} path to create or replace a schema ${schemaPath}/schema/
|
||||
* @objectPath {string} path where object are store
|
||||
* @objectName {string} name of the object
|
||||
* @schema {object} the json schema for this object
|
||||
* @lgjson {object} the json file for a specific language
|
||||
* @lg {string} the 2 letters language
|
||||
*
|
||||
* a shema :
|
||||
* schemaPath/schema/objectName.json
|
||||
* /lg/objectName_{lg}.json
|
||||
* an object :
|
||||
* objectPath/objectName/idx/confjson ={"schema":"relativpathfile or http"}
|
||||
* /uniqueid.json defining schema
|
||||
*
|
||||
*/
|
||||
/**
|
||||
* @api createObject: create a space to host object
|
||||
*
|
||||
* @source {string} "new", url,
|
||||
* @schemapath {string} path to create or replace a schema ${schemaPath}/schema/
|
||||
* @objectPath {string} path where object are store
|
||||
* @objectName {string} name of the object
|
||||
* @schema {object} the json schema for this object
|
||||
* @lgjson {object} the json file for a specific language
|
||||
* @lg {string} the 2 letters language
|
||||
*
|
||||
* Setup a new object localy =>
|
||||
* source
|
||||
*
|
||||
* - from scratch =>
|
||||
* Create
|
||||
* - from a synchronization
|
||||
* Download from source all_{apxid}.json
|
||||
*
|
||||
*
|
||||
*/
|
||||
Odmdb.createObject = (
|
||||
source,
|
||||
schemaPath,
|
||||
objectPath,
|
||||
objectName,
|
||||
schema,
|
||||
lgjson,
|
||||
lg
|
||||
) => {
|
||||
if (!fs.existsSync(schemaPath)) {
|
||||
return {
|
||||
status: 404,
|
||||
@ -85,165 +130,99 @@ Odmdb.setObject = (schemaPath, objectPath, objectName, schema, lgjson, lg) => {
|
||||
return { status: 200 };
|
||||
};
|
||||
|
||||
Odmdb.schema = (schemaPath, objectName, withschemacheck) => {
|
||||
// Return schema if exist and objectpath contain objectName { status:200;data:schema}
|
||||
if (!fs.existsSync(`${schemaPath}/${objectName}`))
|
||||
return {
|
||||
status: 404,
|
||||
info: "|odmdb|schemapathnamedoesnotexist",
|
||||
moreinfo: `${schemaPath}/${objectName}`,
|
||||
};
|
||||
if (!fs.existsSync(`${objectPath}/schema/${objectName}.json`)) {
|
||||
return {
|
||||
status: 404,
|
||||
info: `|odmdb|schemanotfound`,
|
||||
moreinfo: `file not found ${schemaPath}/schema/${objectName}.json`,
|
||||
};
|
||||
}
|
||||
const schema = fs.readJsonSync(`${schemaPath}/schema/${objectName}.json`);
|
||||
// check schema apx validity specificities primary unique ans searchindex
|
||||
if (withschemacheck) {
|
||||
if (!schema.apxprimarykey) {
|
||||
// code 422: unprocessable Content
|
||||
return {
|
||||
status: 422,
|
||||
info: "|Odmdb|apxprimarykeynotfound",
|
||||
moreinfo: `${schemaPath}/schema/${objectName}.json`,
|
||||
};
|
||||
} else {
|
||||
if (
|
||||
!(
|
||||
schema.apxsearchindex[schema.apxprimarykey] &&
|
||||
schema.apxsearchindex[schema.apxprimarykey].list
|
||||
)
|
||||
) {
|
||||
return {
|
||||
status: 422,
|
||||
info: "|Odmdb|apxprimaryketnotinsearchindexlist",
|
||||
moreinfo: `${schemaPath}/schema/${objectName}.json`,
|
||||
};
|
||||
}
|
||||
if (schema.apxuniquekey) {
|
||||
schema.apxuniquekey.forEach((k) => {
|
||||
if (
|
||||
!(
|
||||
schema.apxsearchindex[k] &&
|
||||
schema.apxsearchindex[k][schema.apxprimarykey]
|
||||
)
|
||||
) {
|
||||
return {
|
||||
status: 422,
|
||||
info: "|Odmdb|apxuniquekeynotinsearchindex",
|
||||
moreinfo: `${schemaPath}/schema/${objectName}.json`,
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
const validschema = Checkjson.schema.validation(schema);
|
||||
if (validschema.status != 200) return validschema;
|
||||
}
|
||||
return {
|
||||
/**
|
||||
* Update an object
|
||||
* @param {string} objectPathname
|
||||
* @param {object} meta update request
|
||||
* lg:
|
||||
* lgobj: object to store in /lg/objectname_lg.json
|
||||
* schema: an update schema
|
||||
* @return {status, ref:"Odmdb", msg:"", data}
|
||||
*
|
||||
* Create a tmp object env and check existing object to identify any issues
|
||||
* If all is fine then apply change by replacing
|
||||
*/
|
||||
Odmdb.updateObject = (objectPathname, meta) => {};
|
||||
|
||||
/**
|
||||
* Get a schema from objectPathname
|
||||
*
|
||||
* todo only local schema => plan a sync each 10minutes
|
||||
* @schemaPath local path adminapi/schema/objectName.json or /tribename/schema/objectName
|
||||
* @validschema boolean if necessary to check schema or not mainly use when change schema
|
||||
* @return {status:200,data:{conf:"schemaconf",schema:"schemacontent"} }
|
||||
*/
|
||||
Odmdb.Schema = (objectPathname, validschema) => {
|
||||
const confschema = fs.readJsonSync(`${objectPathname}/conf.json`);
|
||||
let schemaPath = confschema.schema;
|
||||
const res = {
|
||||
status: 200,
|
||||
data: schema,
|
||||
ref: "Odmdb",
|
||||
msg: "getschema",
|
||||
data: { conf: confschema },
|
||||
};
|
||||
};
|
||||
|
||||
//Odmdb.Checkjson = (objectPath, objectName, data, withschemacheck) => {
|
||||
/*
|
||||
@objectPath path to the folder that contain /objects/objectName/ /lg/objectName_{lg}.json /schema/objectName.json
|
||||
@objectName name of object
|
||||
@data data to check based on schema objectName definition
|
||||
|
||||
@return status:200 Data is consistent with schema and primarykey does not exist
|
||||
status:201 Data is consistent with schema and primarykey does already exist
|
||||
status:other means unconsistent schema:
|
||||
404: schema does not exist
|
||||
or unconsitent data and schema from Checkjson.js Checkjson.schema.data
|
||||
|
||||
*/
|
||||
/* const res = { status: 200,ref="Odmdb",msg:"",data:{} };
|
||||
//get schema link of object
|
||||
const schemaPath = fs.readJsonSync(
|
||||
`${objectPath}/${objectName}/idx/conf.json`
|
||||
)["schema"];
|
||||
if (schemaPath.substring(0, 4) == "http") {
|
||||
// lance requete http pour recuperer le schema
|
||||
} else {
|
||||
res.data.schema = Odmdb.schema(objectPath, objectName, withschemacheck);
|
||||
}
|
||||
// check schema validity in case withschemacheck
|
||||
if (schema.status != 200) return ;
|
||||
console.log("SCHEMA for checking:");
|
||||
console.log(schema.data);
|
||||
console.log("DATA to check:");
|
||||
console.log(data);
|
||||
// withschemacheck at false, if check then it is done at Odmdb.schema
|
||||
const validate = Checkjson.schema.data(schema.data, data, false);
|
||||
if (validate.status != 200) {
|
||||
return validate;
|
||||
}
|
||||
if (
|
||||
schema.data.apxprimarykey &&
|
||||
data[k] &&
|
||||
fs.existsSync(`${objectPath}/${objectName}/${data[k]}.json}`)
|
||||
) {
|
||||
res.status = 201; // means created => exist an object with this primary key
|
||||
}
|
||||
if (schema.data.apxuniquekey) {
|
||||
schema.data.apxuniquekey.forEach((k) => {
|
||||
if (
|
||||
data[k] &&
|
||||
fs.existsSync(
|
||||
`${objectPath}/${objectName}/searchindex/${objectName}_${k}_${schema.data.apxprimarykey}.json}`
|
||||
) &&
|
||||
fs.readJsonSync(
|
||||
`${objectPath}/${objectName}/searchindex/${objectName}_${k}_${schema.data.apxprimarykey}.json}`
|
||||
)[k]
|
||||
) {
|
||||
res.status = 201; // means created => exist as primary key
|
||||
}
|
||||
});
|
||||
}
|
||||
return res;
|
||||
};
|
||||
*/
|
||||
Odmdb.getSchema=async (schemaPath,validschema)=>{
|
||||
/**
|
||||
* @schemaPath public http link or local path adminapi/schema/objectName.json or /tribename/schema/objectName
|
||||
* @return schema or {}
|
||||
*/
|
||||
const res={status:200,data:{schema:{}}}
|
||||
if (schemaPath.slice(-5)!=".json") schemaPath+=".json";
|
||||
if (schemaPath.slice(-5) != ".json") schemaPath += ".json";
|
||||
if (schemaPath.substring(0, 4) == "http") {
|
||||
// lance requete http pour recuperer le schema avec un await axios
|
||||
} else {
|
||||
if (schemaPath.substring(0,9)=="adminapi/"){
|
||||
schemaPath=`${conf.dirapi}/${schemaPath}`
|
||||
}else{
|
||||
schemaPath=`${conf.dirtown}/tribes/${schemaPath}`
|
||||
if (schemaPath.substring(0, 9) == "adminapi/") {
|
||||
schemaPath = `${conf.dirapi}/${schemaPath}`;
|
||||
} else {
|
||||
schemaPath = `${conf.dirtown}/tribes/${schemaPath}`;
|
||||
}
|
||||
if (!fs.existsSync(schemaPath)){
|
||||
return {status:404, ref:"Odmdb", msg:"schemanotfound", data:{schemaPath,schema:{}}}
|
||||
if (!fs.existsSync(schemaPath)) {
|
||||
return {
|
||||
status: 404,
|
||||
ref: "Odmdb",
|
||||
msg: "schemanotfound",
|
||||
data: { schemaPath, schema: {} },
|
||||
};
|
||||
}
|
||||
res.data.schema=fs.readJsonSync(schemaPath)
|
||||
if (validschema ||1==1){
|
||||
const check = Checkjson.schema.validation(res.data.schema)
|
||||
if (check.err.length>0) {
|
||||
res.status=check.status
|
||||
res.data.err=check.err
|
||||
res.data.schema = fs.readJsonSync(schemaPath);
|
||||
if (!res.data.schema.apxid) {
|
||||
return {
|
||||
status: 406,
|
||||
ref: "Odmdb",
|
||||
msg: "missingprimarykey",
|
||||
data: {},
|
||||
};
|
||||
}
|
||||
if (res.data.schema.apxidx) {
|
||||
//add apxidx to apxuniquekey in case not
|
||||
if (!res.data.schema.apxuniquekey.includes(res.data.schema.apxid)) {
|
||||
res.data.schema.apxuniquekey.push(res.data.schema.apxid);
|
||||
}
|
||||
res.data.schema.apxidx.forEach((idx) => {
|
||||
if (
|
||||
idx.objkey &&
|
||||
!res.data.schema.apxuniquekey.includes(idx.keyval) &&
|
||||
!idx.objkey.includes(res.data.schema.apxid)
|
||||
) {
|
||||
return {
|
||||
status: 406,
|
||||
ref: "Odmdb",
|
||||
msg: "unconsistencyapxidx",
|
||||
data: {
|
||||
name: idx.name,
|
||||
keyval: idx.keyval,
|
||||
objkey: idx.objkey,
|
||||
apxid: res.data.schema.apxid,
|
||||
},
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
if (validschema || 1 == 1) {
|
||||
// return {status:200, ref, msg} or {status!:200,multimsg:[{ref,msg;data}]}
|
||||
const check = Checkjson.schema.validation(res.data.schema);
|
||||
if (check.status != 200) {
|
||||
res.multimsg = check.multimsg;
|
||||
res.status = check.status;
|
||||
}
|
||||
//check json schema for Odmdb context
|
||||
if (!res.data.schema.apxprimarykey || !res.data.schema.properties[res.data.schema.apxprimarykey]){
|
||||
// primarykey require for Odmdb
|
||||
res.status=406
|
||||
if (!res.data.err) res.data.err=[];
|
||||
res.data.err.push({ref:"Odmdb",msg:"novalidprimarykey",data:{apxprimarykey:res.data.schema.apxprimarykey}})
|
||||
}
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
return res;
|
||||
};
|
||||
Odmdb.search = (objectPath, objectName, search) => {
|
||||
/*
|
||||
@search= {
|
||||
@ -263,96 +242,367 @@ Odmdb.search = (objectPath, objectName, search) => {
|
||||
const schema = Odmdb.schema(objectPath, objectName);
|
||||
if (schema.status != 200) return schema;
|
||||
};
|
||||
Odmdb.get = (objectPath, objectName, uuidprimarykeyList, fieldList) => {
|
||||
/*
|
||||
@objectPath where object are store (where /object/conf.json indicate where the schema is)
|
||||
@uuidprimarykeyList list of uuid requested
|
||||
@fieldList key to return for each object
|
||||
Return {status:200; data:{uuid:{data filter by @fieldList},uuid:"notfound"}}
|
||||
*/
|
||||
|
||||
/**
|
||||
* To get an array of item (itm) per primarykey with a list of field
|
||||
* Object are store in objectPath/objectName/conf.json contain
|
||||
*
|
||||
* @objectPathname where object are store (where /object/conf.json indicate where the schema is)
|
||||
* @uuidprimarykeyList list of uuid requested
|
||||
* @role {xalias,xprofiles} allow to get accessright come from header
|
||||
* @propertiesfilter (optionnal) key to return for each object (if undefined then return all)
|
||||
* @Return {status:200; data:{uuid:{data filter by @propertiesfilter},uuid:"notfound"}}
|
||||
*/
|
||||
Odmdb.reads = (objectPathname, apxidlist, role, propertiesfilter) => {
|
||||
const res = { status: 200, data: {} };
|
||||
uuidprimarykeyList.forEach(id => {
|
||||
if (fs.existsSync(`${objectPath}/${objectName}/itm/${id}.json`)) {
|
||||
const objectdata = fs.readJsonSync(
|
||||
`${objectPath}/${objectName}/itm/${id}.json`
|
||||
);
|
||||
if (!fieldList) {
|
||||
res.data[id]=objectdata;
|
||||
const getschema = Odmdb.Schema(objectPathname, true);
|
||||
if (getschema.status != 200) return getschema;
|
||||
// Test if readable at least if owner
|
||||
role.xprofils.push("owner");
|
||||
const accessright = (Odmdb.accessright =
|
||||
(getschema.data.schema.apxaccessright, role.xprofils));
|
||||
if (!accessright.R) {
|
||||
return {
|
||||
status: 403,
|
||||
ref: "Odmdb",
|
||||
msg: "accessforbidden",
|
||||
data: { crud: "R", accessright },
|
||||
};
|
||||
}
|
||||
apxidlist.forEach((id) => {
|
||||
if (fs.existsSync(`${objectPathname}/itm/${id}.json`)) {
|
||||
const objectdata = fs.readJsonSync(`${objectPathname}/itm/${id}.json`);
|
||||
if (objectdata.owner && objectdata.owner == role.xalias) {
|
||||
if (!role.xprofils.includes("owner")) role.xprofils.push("owner");
|
||||
} else {
|
||||
if (role.xprofils.includes("owner"))
|
||||
role.xprofils = role.xprofils.filter((e) => e !== "owner");
|
||||
}
|
||||
const accessright = Odmdb.accessright(
|
||||
getschema.data.schema.apxaccessright,
|
||||
role
|
||||
);
|
||||
if (!accessright.R) {
|
||||
res.data[id] = "forbiden";
|
||||
} else {
|
||||
let newpropertiesfilter = Object.keys(objectdata);
|
||||
if (accessright.R.length > 0) {
|
||||
const setaccess = new Set(accessright.R);
|
||||
if (!propertiesfilter) propertiesfilter = Object.keys(objectdata);
|
||||
newpropertiesfilter = propertiesfilter.filter((f) =>
|
||||
setaccess.has(f)
|
||||
);
|
||||
}
|
||||
const objinfo = {};
|
||||
fieldlList.forEach((k) => {
|
||||
newpropertiesfilter.forEach((k) => {
|
||||
if (objectdata[k]) objinfo[k] = objectdata[k];
|
||||
});
|
||||
res.data[id]=objinfo;
|
||||
res.data[id] = objinfo;
|
||||
}
|
||||
} else {
|
||||
res.data[id]="notfound";
|
||||
res.data[id] = "notfound";
|
||||
}
|
||||
});
|
||||
return res;
|
||||
};
|
||||
Odmdb.create = (objectPath, objectName, data, accessright) => {
|
||||
/*
|
||||
Create an objects data into objectName
|
||||
@objectPath path to the folder that contain /objects/objectName/ /objectsInfo/objectName_lg.json /objectsMeta/objectName.json
|
||||
@objectName name of object
|
||||
@data data to check based on objectsMeta definition
|
||||
@accessright a string with accessright of the user on this objectName ex: "CRUDO" or "R" or "O"
|
||||
*/
|
||||
/**
|
||||
* Convert profils in accessright
|
||||
* @param {*} apxaccessright from schema object {profilname:{R}}
|
||||
* @param {*} role {xprofils,xalias} accessible after isAuthenticated
|
||||
* @returns access right to C create if present, to read (properties list or all if empty), to Update properties list or all if empty, D elete
|
||||
* example: {"C":[],"R":[properties list],"U":[properties ist],"D":[]}
|
||||
*/
|
||||
Odmdb.accessright = (apxaccessrights, role) => {
|
||||
const accessright = {};
|
||||
role.xprofils.forEach((p) => {
|
||||
if (apxaccessrights[p]) {
|
||||
Object.keys(apxaccessrights[p]).forEach((act) => {
|
||||
if (!accessright[act]) {
|
||||
accessright[act] = apxaccessrights[p][act];
|
||||
} else {
|
||||
accessright[act] = [
|
||||
...new Set([...accessright[act], ...apxaccessrights[p][act]]),
|
||||
];
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
return accessright;
|
||||
};
|
||||
Odmdb.update = async (objectPath, objectName, data, id, accessright) => {
|
||||
/*
|
||||
Create an objects data into objectName
|
||||
@objectPath path to the folder that contain /objects/objectName/ /objectsInfo/objectName_lg.json /objectsMeta/objectName.json
|
||||
@objectName name of object
|
||||
@data data to check based on objectsMeta definition
|
||||
*/
|
||||
if (!fs.existsSync(`${objectPath}/${objectName}/itm/${id}.json`)){
|
||||
return {status:404,ref:"Odmdb",msg:"itmnotfound",data:{objectPath,objectName,id}}
|
||||
}
|
||||
const currentobj=fs.readJSONSync(`${objectPath}/${objectName}/itm/${id}.json`)
|
||||
Object.keys(data).forEach(k=>{
|
||||
currentobj[k]=data[k]
|
||||
})
|
||||
if (currentobj.dt_update) currentobj.dt_update=dayjs().toISOString();
|
||||
const schemaPath = fs.readJsonSync(
|
||||
`${objectPath}/${objectName}/conf.json`
|
||||
)["schema"];
|
||||
const getschema = await Odmdb.getSchema(schemaPath);
|
||||
if (getschema.status!=200 || Object.keys(getschema.data.schema).length==0) {
|
||||
console.log('this is not suppose to happen in Odmdb',Object.keys(getschema.data.schema))
|
||||
return getschema
|
||||
}
|
||||
const schema=getschema.data.schema;
|
||||
const check = Checkjson.schema.data(schema,currentobj,false);
|
||||
console.log(check)
|
||||
if (check.err.length==0){
|
||||
// update
|
||||
fs.outputJsonSync(`${objectPath}/${objectName}/itm/${id}.json`,currentobj)
|
||||
//@todo select index file to generate depending of k update currently we re-index all
|
||||
/**
|
||||
* CUD a data itm into objectPathname if checkJson is valid
|
||||
* and update idx
|
||||
* idx is upto date for unique properties but not for list
|
||||
* @param {string} objectpathname folder name where object are stored
|
||||
* @param {object} itm an object respecting the checkJson schema in objectPathname/conf.json
|
||||
* @param {string} crud: C reate U pdate D elete
|
||||
* @param {array} role {xprofils,xalias} xprofils list of profils like anonymous,pagans, person owner is deuce if object properties owner is alias
|
||||
|
||||
return {status:200,ref:"Odmdb",msg:"updatesuccessfull"}
|
||||
}else{
|
||||
return {status:409, ref:"Odmdb",msg:"datavsschemaunconsistent",data:check.err}
|
||||
}
|
||||
};
|
||||
Odmdb.delete = (objectPath, objectName, data,accessright) => {
|
||||
/*
|
||||
Create an objects data into objectName
|
||||
@objectPath path to the folder that contain /objects/objectName/ /objectsInfo/objectName_lg.json /objectsMeta/objectName.json
|
||||
@objectName name of object
|
||||
@data data to check based on objectsMeta definition
|
||||
*/
|
||||
};
|
||||
/*console.log("test Odmdb");
|
||||
console.log(
|
||||
Odmdb.check(
|
||||
"/media/phil/usbfarm/apxtrib/nationchains/socialworld/objects",
|
||||
"nations",
|
||||
{ nationId: "123", status: "unchain" }
|
||||
)
|
||||
);*/
|
||||
* */
|
||||
|
||||
Odmdb.cud = (objectPathname, crud, itm, role) => {
|
||||
const getschema = Odmdb.Schema(objectPathname, true);
|
||||
if (getschema.status != 200) return getschema;
|
||||
|
||||
if (!itm[getschema.data.schema.apxid]) {
|
||||
return {
|
||||
status: 406,
|
||||
ref: "Odmdb",
|
||||
msg: "apxidmissing",
|
||||
data: { missingkey: getschema.data.schema.apxid },
|
||||
};
|
||||
}
|
||||
const existid = fs
|
||||
.readJSONSync(
|
||||
`${objectPathname}/idx/lst_${getschema.data.schema.apxid}.json`
|
||||
)
|
||||
.includes(itm[getschema.data.schema.apxid]);
|
||||
if (existid && crud == "C") {
|
||||
return {
|
||||
status: 406,
|
||||
ref: "Odmdb",
|
||||
msg: "alreadyexist",
|
||||
data: {
|
||||
objectname: path.basename(objectPathname),
|
||||
key: getschema.data.schema.apxid,
|
||||
val: itm[getschema.data.schema.apxid],
|
||||
},
|
||||
};
|
||||
}
|
||||
if (!existid && ["U", "D"].includes(crud)) {
|
||||
return {
|
||||
status: 406,
|
||||
ref: "Odmdb",
|
||||
msg: "doesnotexist",
|
||||
data: {
|
||||
objectname: path.basename(objectPathname),
|
||||
key: getschema.data.schema.apxid,
|
||||
val: itm[getschema.data.schema.apxid],
|
||||
},
|
||||
};
|
||||
}
|
||||
const itmold = existid
|
||||
? fs.readJSONSync(
|
||||
`${objectPathname}/itm/${itm[getschema.data.schema.apxid]}.json`
|
||||
)
|
||||
: {};
|
||||
if (existid && itmold.owner && itmold.owner == role.xalias) {
|
||||
role.xprofils.push("owner");
|
||||
} else {
|
||||
// set owner cause this is a Create
|
||||
itm.owner = role.xalias;
|
||||
}
|
||||
//get accessrigh {C:[],R:[],U:[],D:[]} if exist means authorize, if array contain properties (for R and U) right is only allowed on properties
|
||||
const accessright = Odmdb.accessright(
|
||||
getschema.data.schema.apxaccessrights,
|
||||
role
|
||||
);
|
||||
console.log("accessright", accessright);
|
||||
if (
|
||||
(crud == "C" && !accessright.C) ||
|
||||
(crud == "D" && !accessright.D) ||
|
||||
(crud == "U" && !accessright.U)
|
||||
) {
|
||||
return {
|
||||
status: 403,
|
||||
ref: "Odmdb",
|
||||
msg: "accessforbidden",
|
||||
data: { crud, accessright },
|
||||
};
|
||||
}
|
||||
//delete or save
|
||||
if (crud == "D") {
|
||||
itmold["dt_delete"] = dayjs();
|
||||
fs.outputJSONSync(
|
||||
`${objectPathname}/delitm/${itmold[getschema.data.schema.apxid]}.json`,
|
||||
itmold
|
||||
);
|
||||
fs.rmSync(
|
||||
`${objectPathname}/itm/${itmold[getschema.data.schema.apxid]}.json`
|
||||
);
|
||||
} else {
|
||||
// if Create Update erase old version
|
||||
let itmtostore = itm;
|
||||
if (crud == "U" && accessright.U.length > 0) {
|
||||
itmtostore = itmold;
|
||||
accessright.U.forEach((p) => {
|
||||
itmtostore[p] = itm[p];
|
||||
});
|
||||
itmtostore.dt_update = dayjs();
|
||||
}
|
||||
if (crud == "C") itmtostore.dt_create = dayjs();
|
||||
// check consistency of datatostore
|
||||
const chkdata = Checkjson.schema.data(
|
||||
getschema.data.schema,
|
||||
itmtostore,
|
||||
false
|
||||
);
|
||||
if (chkdata.status != 200) return chkdata;
|
||||
if (!getschema.data.schema.apxuniquekey)
|
||||
getschema.data.schema.apxuniquekey = [];
|
||||
|
||||
fs.outputJSONSync(
|
||||
`${objectPathname}/itm/${chkdata.data.apxid}.json`,
|
||||
chkdata.data.itm
|
||||
);
|
||||
}
|
||||
console.log("getschema", getschema);
|
||||
//update idx
|
||||
Odmdb.idxfromitm(
|
||||
objectPathname,
|
||||
crud,
|
||||
itm,
|
||||
itmold,
|
||||
[],
|
||||
getschema.data.schema
|
||||
);
|
||||
getschema.data.conf.lastupdatedata = dayjs();
|
||||
fs.outputJSONSync(`${objectPathname}/conf.json`, getschema.data.conf);
|
||||
return {
|
||||
status: 200,
|
||||
ref: "Odmdb",
|
||||
msg: "cudsuccessfull",
|
||||
data: { itm: chkdata.data.itm },
|
||||
};
|
||||
};
|
||||
/**
|
||||
* create/update idx from itm(s)
|
||||
*
|
||||
* @param {string} objectPathname
|
||||
* @param {object} itm item to Create or to Update or {} if crud == I or crud == D
|
||||
* @param {object} itmold (current item) if crud == U or D to get previous itm before change or {} if crud==I or C
|
||||
* @param {letter} crud CUDI C add, U update, D delete I reindex
|
||||
* @param {array} idx if specific request to rebuild list of idx only if [] then use schema one
|
||||
* @param {object} schema if empty it use schema from Odmdb.Schema().data.schema
|
||||
*
|
||||
* example create alias 12 name fred:
|
||||
* Odmdb.idxfromitm('.../tribes/ndda/persons',"C",{alias:'12',name:"fred"},{},[], {person schema})
|
||||
* example update alias 12 in name freddy:
|
||||
* Odmdb.idxfromitm('.../tribes/ndda/persons',"U",{alias:'12',name:"freddy"},{alias:'12',name:"fred"},[], {person schema})
|
||||
* example delete alias 12:
|
||||
* Odmdb.idxfromitm('.../tribes/ndda/persons',"D",{},{alias:'12',name:"fred"},[], {person schema})
|
||||
* example to rebuild all index from scratch
|
||||
* Odmdb.idxfromitm('.../tribes/ndda/persons',"I",{},{},[], {person schema})
|
||||
* example to rebuild only publickey_alias index from scratch
|
||||
* Odmdb.idxfromitm('.../tribes/ndda/pagans',"I",{},{},[{ name:"publickey_alias",keyval:"publickey",objkey:["alias"]}], {pagans schema})
|
||||
*
|
||||
*/
|
||||
Odmdb.idxfromitm = (objectPathname, crud, itm, itmold, idxs = [], schema) => {
|
||||
console.log(`idxfromitem for ${objectPathname} action:${crud}`);
|
||||
if (!schema || !schema.apxid) {
|
||||
const getschema = Odmdb.Schema(objectPathname, true);
|
||||
if (getschema.status != 200) return getschema;
|
||||
schema = getschema.data.schema;
|
||||
}
|
||||
console.log(schema.apxuniquekey);
|
||||
const itms = crud == "I" ? glob.sync(`${objectPathname}/itm/*.json`) : [itm];
|
||||
console.log(itms);
|
||||
if (crud == "I") {
|
||||
//reinit all idx
|
||||
idxs.forEach((idx) => {
|
||||
fs.remove(`${objectPathname}/idx/${idx.name}.json`);
|
||||
});
|
||||
}
|
||||
let idxtoreindex = []; //store index that has to be reprocessto get full context
|
||||
idxs = idxs.length == 0 ? schema.apxidx : idxs; // get all index if none
|
||||
itms.forEach((i) => {
|
||||
if (crud == "I") {
|
||||
itm = fs.readJSONSync(i);
|
||||
}
|
||||
//console.log(itm);
|
||||
idxs.forEach((idx) => {
|
||||
const keyvalisunique = schema.apxuniquekey.includes(idx.keyval); // check if keyval is unique mean store as an object (or string) else store as an array
|
||||
const idxsrc = `${objectPathname}/idx/${idx.name}.json`;
|
||||
const idxinit = idx.name.substring(0, 4) == "lst_" ? [] : {}; // select type of idx (array or object)
|
||||
let idxfile = !fs.existsSync(idxsrc) ? idxinit : fs.readJSONSync(idxsrc);
|
||||
if (idx.name.substring(0, 4) == "lst_") {
|
||||
if (["D", "U"].includes(crud)) {
|
||||
if (keyvalisunique) {
|
||||
idxfile = idxfile.filter((e) => e !== itmold[idx.keyval]);
|
||||
} else {
|
||||
idxtoreindex.push(idx); //@todo
|
||||
}
|
||||
}
|
||||
console.log(idx.keyval);
|
||||
console.log(itm[idx.keyval]);
|
||||
|
||||
if (
|
||||
["C", "U", "I"].includes(crud) &&
|
||||
!idxfile.includes(itm[idx.keyval])
|
||||
) {
|
||||
idxfile.push(itm[idx.keyval]);
|
||||
}
|
||||
} else {
|
||||
if (!idx.objkey) {
|
||||
//mean all properties
|
||||
idx.objkey = Object.keys(schema.properties);
|
||||
}
|
||||
if (keyvalisunique && idx.objkey.length == 1) {
|
||||
if (["D", "U"].includes(crud)) {
|
||||
delete idxfile[itmold[idx.keyval]];
|
||||
} else {
|
||||
idxfile[itm[idx.keyval]] = itm[idx.objkey[0]];
|
||||
}
|
||||
}
|
||||
if (keyvalisunique && idx.objkey.length > 1) {
|
||||
if (["D", "U"].includes(crud)) {
|
||||
delete idxfile[itmold[idx.keyval]];
|
||||
} else {
|
||||
const itmfilter = {};
|
||||
idx.objkey.forEach((i) => {
|
||||
if (itm[i]) itmfilter[i] = itm[i];
|
||||
});
|
||||
idxfile[itm[idx.keyval]] = itmfilter;
|
||||
}
|
||||
}
|
||||
if (!keyvalisunique && idx.objkey.length == 1) {
|
||||
if (
|
||||
["D", "U"].includes(crud) &&
|
||||
idxfile[itmold[idx.keyval]].IndexOf(itmold[idx.objkey[0]]) > -1
|
||||
) {
|
||||
// U because need to remove previous value before adding it
|
||||
idxfile[itmold[idx.keyval]].splice(
|
||||
idxfile[itmold[idx.keyval]].IndexOf(itmold[idx.objkey[0]]),
|
||||
1
|
||||
);
|
||||
}
|
||||
if (["C", "U", "I"].includes(crud)) {
|
||||
if (!idxfile[itm[idx.keyval]]) idxfile[itm[idx.keyval]] = [];
|
||||
if (!idxfile[itm[idx.keyval]].includes(itm[idx.objkey[0]])) {
|
||||
idxfile[itm[idx.keyval]].push(itm[idx.objkey[0]]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!keyvalisunique && idx.objkey.length > 1) {
|
||||
if (["D", "U"].includes(crud) && idxfile[itmold[idx.keyval]]) {
|
||||
// U because need to remove previous value before adding it
|
||||
let arrayofit = [];
|
||||
idxfile[itmold[idx.keyval]].forEach((it) => {
|
||||
if (it[schema.apxid] != itm[schema.apxid]) arrayofit.push(it);
|
||||
});
|
||||
idxfile[itmold[idx.keyval]] = arrayofit;
|
||||
}
|
||||
if (["C", "U", "I"].includes(crud)) {
|
||||
const itmfilter = {};
|
||||
idx.objkey.forEach((i) => {
|
||||
if (itm[i]) itmfilter[i] = itm[i];
|
||||
});
|
||||
if (!idxfile[itm[idx.keyval]]) idxfile[itm[idx.keyval]] = [];
|
||||
idxfile[itm[idx.keyval]].push(itmfilter);
|
||||
}
|
||||
}
|
||||
}
|
||||
fs.outputJSONSync(idxsrc, idxfile);
|
||||
});
|
||||
});
|
||||
if (crud != "I") {
|
||||
//update lastupdatedata to inform something change
|
||||
const confschema = fs.readJSONSync(`${objectPathname}/conf.json`);
|
||||
confschema.lastupdatedata = dayjs();
|
||||
fs.outputJSONSync(`${objectPathname}/conf.json`, getschema.data.conf);
|
||||
}
|
||||
return { status: 200, ref: "Odmdb", msg: "successreindex", data: {} };
|
||||
};
|
||||
Odmdb.updatefromidxall = (objectname, idxname, data, lastupdate) => {
|
||||
/**
|
||||
* Update all itm of objectname from index idx/idxname with data
|
||||
|
@ -4,6 +4,8 @@ const dayjs = require("dayjs");
|
||||
const fs = require("fs-extra");
|
||||
const axios = require("axios");
|
||||
const openpgp = require("openpgp");
|
||||
const Notifications = require("../models/Notifications.js");
|
||||
const Odmdb = require("../models/Odmdb.js");
|
||||
|
||||
/*if (fs.existsSync("../../nationchains/tribes/conf.json")) {
|
||||
conf = require("../../nationchains/tribes/conf.json");
|
||||
@ -16,23 +18,42 @@ const conf = require(`${process.env.dirtown}/conf.json`);
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
const Pagans = {};
|
||||
|
||||
/**
|
||||
* Remove authentification token after a logout
|
||||
* @param {string} alias
|
||||
* @param {string} tribe
|
||||
* @param {integer} xdays
|
||||
* @param {string} xhash
|
||||
* @returns {status:200, ref:"Pagans",msg:"logout"}
|
||||
* tmpfs name file has to be on line with the tmpfs create by isAuthenticated
|
||||
* tmpfs contain profils name for a tribe/
|
||||
*/
|
||||
Pagans.logout = (alias, tribe, xdays, xhash) => {
|
||||
//console.log(alias, tribe, xdays, xhash);
|
||||
// inline with middleware isAuthenticated.js
|
||||
let tmpfs = `${process.env.dirtown}/tmp/tokens/${alias}_${tribe}_${xdays}`;
|
||||
//max filename in ext4: 255 characters
|
||||
tmpfs += `_${xhash.substring(150, 150 + tmpfs.length - 249)}.json`;
|
||||
fs.remove(tmpfs);
|
||||
return { status: 200, ref: "Pagans", msg: "logout" };
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {string} alias a alias that exist or not
|
||||
* @return {object} { status: 200, ref:"pagans",msg:"aliasexist",data: { alias, publicKey } }
|
||||
* { status: 404, ref:"pagans",msg:"aliasdoesnotexist",data: { alias} }
|
||||
*
|
||||
**/
|
||||
Pagans.getalias = (alias) => {
|
||||
/**
|
||||
* @param {string} alias a alias that exist or not
|
||||
* @return {object} { status: 200, ref:"pagans",msg:"aliasexist",data: { alias, publicKey } }
|
||||
* { status: 404, ref:"pagans",msg:"aliasdoesnotexist",data: { alias} }
|
||||
*
|
||||
**/
|
||||
console.log(`${conf.dirapi}/nationchains/pagans/itm/${alias}.json`);
|
||||
//bypass Odmdb cause all is public
|
||||
if (fs.existsSync(`${conf.dirapi}/nationchains/pagans/itm/${alias}.json`)) {
|
||||
return {
|
||||
status: 200,
|
||||
ref: "Pagans",
|
||||
msg: "aliasexist",
|
||||
data: fs.readJsonSync(
|
||||
data: fs.readJSONSync(
|
||||
`${conf.dirapi}/nationchains/pagans/itm/${alias}.json`
|
||||
),
|
||||
};
|
||||
@ -46,52 +67,56 @@ Pagans.getalias = (alias) => {
|
||||
}
|
||||
};
|
||||
|
||||
Pagans.getperson = (alias, tribeid) => {
|
||||
/**
|
||||
* @param {string} alias that exist
|
||||
* @param {string} tribeId that exist with a person alias
|
||||
* @return {object} { status: 200, ref:"pagans",msg:"personexist",data: { person } }
|
||||
* { status: 404, ref:"pagans",msg:"persondoesnotexist",data: { person } }
|
||||
*
|
||||
**/
|
||||
if (
|
||||
fs.existsSync(`${conf.dirtown}/tribes/${tribeid}/person/itm/${alias}.json`)
|
||||
) {
|
||||
const person = fs.readJsonSync(
|
||||
`${conf.dirtown}/tribes/${tribeid}/person/itm/${alias}.json`
|
||||
);
|
||||
delete person.auth;
|
||||
return {
|
||||
status: 200,
|
||||
ref: "Pagans",
|
||||
msg: "personexist",
|
||||
data: person,
|
||||
};
|
||||
} else {
|
||||
/**
|
||||
* @param {string} alias that exist
|
||||
* @param {string} tribeId that exist with a person alias
|
||||
* @return {object} { status: 200, ref:"pagans",msg:"personexist",data: { person } }
|
||||
* { status: 404, ref:"pagans",msg:"persondoesnotexist",data: { person } }
|
||||
*
|
||||
**/
|
||||
Pagans.getperson = (tribeid, alias, role) => {
|
||||
const objlst = Odmdb.reads(
|
||||
`${conf.dirtown}/tribes/${tribeid}/persons`,
|
||||
[alias],
|
||||
role
|
||||
);
|
||||
if (objlst.data[alias] == "notfound") {
|
||||
return {
|
||||
status: 404,
|
||||
ref: "Pagans",
|
||||
msg: "persondoesnotexist",
|
||||
data: { alias, tribeid },
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
status: 200,
|
||||
ref: "Pagans",
|
||||
msg: "personexist",
|
||||
data: objlst.data[alias],
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
Pagans.create = (alias, publicKey) => {
|
||||
Pagans.create = (objpagan, role) => {
|
||||
/**
|
||||
* @param {string} alias a unique alias that identify an identity
|
||||
* @param {string} publicKey a publicKey
|
||||
* @param {object} objpagan {alias,publickey} a unique alias/publickey that identify an identity
|
||||
* @param {array} role {xalias,xprofils} requester and list of profil
|
||||
* @return {object} { status: 200, data: { alias, publicKey } }
|
||||
* xhash was checked by isauthenticated
|
||||
* @todo use Odmdb to add a pagan
|
||||
*/
|
||||
return Odmdb.cud(`${conf.dirapi}/nationchains/pagans`, "C", objpagan, role);
|
||||
/*
|
||||
let apxpagans = {};
|
||||
if (fs.existsSync(`${conf.dirapi}/nationchains/pagans/idx/alias_all.json`)) {
|
||||
apxpagans = fs.readJsonSync(
|
||||
`${conf.dirapi}/nationchains/pagans/idx/alias_all.json`
|
||||
);
|
||||
}
|
||||
apxpagans[alias] = { alias, publicKey };
|
||||
if (apxpagans[objpagan.alias]) {
|
||||
return { status: 409, ref: "Pagans", msg: "aliasexist", data: { alias } };
|
||||
}
|
||||
apxpagans[objpagan.alias] = { alias, publicKey };
|
||||
fs.outputJsonSync(
|
||||
`${conf.dirapi}/nationchains/pagans/idx/alias_all.json`,
|
||||
apxpagans
|
||||
@ -100,52 +125,148 @@ Pagans.create = (alias, publicKey) => {
|
||||
alias,
|
||||
publicKey,
|
||||
});
|
||||
return { status: 200, ref:"Pagans", msg:"identitycreate",data: { alias, publicKey } };
|
||||
return {
|
||||
status: 200,
|
||||
ref: "Pagans",
|
||||
msg: "identitycreate",
|
||||
data: { alias, publicKey },
|
||||
};
|
||||
*/
|
||||
};
|
||||
|
||||
Pagans.personupdate = (alias, tribe, persondata) => {
|
||||
//later use Odmdb ans schema person to manage this
|
||||
/**
|
||||
* @Param {string} alias pagan unique id
|
||||
* @Param {string} tribe tribe id in this town
|
||||
* @Param {object} persondata that respect /nationchains/schema/person.json + nationchains/tribe/tribeid/schema/personextented.json
|
||||
* @return create or update a person /tribe/tribeid/person/alias.json
|
||||
*/
|
||||
let person = {
|
||||
/**
|
||||
* @Param {string} alias pagan unique id
|
||||
* @Param {string} tribeid tribe id in this town
|
||||
* @Param {object} persondata that respect /nationchains/schema/person.json + nationchains/tribe/tribeid/schema/personextented.json
|
||||
* @return create or update a person /tribe/tribeid/person/alias.json
|
||||
* todo later use Odmdb ans schema person to manage this
|
||||
*/
|
||||
Pagans.personupdate = (tribeid, alias, personupdate, role) => {
|
||||
const personinit = {
|
||||
alias: alias,
|
||||
dt_create: dayjs(),
|
||||
accessrights: { profil: "user" },
|
||||
profils: ["person"],
|
||||
};
|
||||
if (
|
||||
fs.existsSync(
|
||||
`${process.env.dirtown}/tribes/${tribe}/person/itm/${alias}.json`
|
||||
)
|
||||
) {
|
||||
person = fs.readJsonSync(
|
||||
`${process.env.dirtown}/tribes/${tribe}/person/itm/${alias}.json`
|
||||
);
|
||||
person.dt_update = dayjs();
|
||||
}
|
||||
Object.keys(persondata).forEach((d) => {
|
||||
person[d] = persondata[d];
|
||||
const personfile = `${process.env.dirtown}/tribes/${tribeid}/person/itm/${alias}.json`;
|
||||
const persondata = fs.existsSync(personfile)
|
||||
? fs.readJSONSync(personfile)
|
||||
: personinit;
|
||||
persondata.dt_update = dayjs();
|
||||
|
||||
Object.keys(personupdate).forEach((d) => {
|
||||
persondata[d] = personupdate[d];
|
||||
});
|
||||
//const checkjson= Checkjson.schema.data = (fs.readJsonSync(`${conf.dirapi}/nationchains/schema/person.json`, person, false)
|
||||
// if checkjson.status==200 create /update with odmdb to update index data
|
||||
// see odmdb that did all and return standard message
|
||||
fs.outputJSONSync(
|
||||
`${process.env.dirtown}/tribes/${tribe}/person/itm/${alias}.json`,
|
||||
person,
|
||||
{
|
||||
space: 2,
|
||||
}
|
||||
);
|
||||
fs.outputJSONSync(personfile, persondata, { space: 2 });
|
||||
return {
|
||||
status: 200,
|
||||
ref: "Pagans",
|
||||
msg: "successfullupdate",
|
||||
data: { tribe: tribe },
|
||||
data: { alias: alias, tribeid: tribeid },
|
||||
};
|
||||
};
|
||||
/**
|
||||
* Send email with alias's keys to email or person alias person.recovery.email
|
||||
*
|
||||
* If email or pubkey is undefined then get data from tribe/person(alias)
|
||||
* Send email with keys
|
||||
*
|
||||
* @param {string} alias
|
||||
* @param {pgpPrivate} privkey
|
||||
* @param {string} passphrase
|
||||
* @param {string} tribe
|
||||
* @param {pgpPublic} pubkey
|
||||
* @param {string} email
|
||||
*/
|
||||
Pagans.sendmailkey = (
|
||||
alias,
|
||||
privatekey,
|
||||
tribeid,
|
||||
passphrase,
|
||||
publickey,
|
||||
email
|
||||
) => {
|
||||
const person = { alias, privatekey, tribeid };
|
||||
console.log(
|
||||
alias,
|
||||
"-",
|
||||
privatekey,
|
||||
"-",
|
||||
tribeid,
|
||||
"-",
|
||||
passphrase,
|
||||
"-",
|
||||
publickey,
|
||||
"-",
|
||||
email
|
||||
);
|
||||
if (!publickey || !email || !passphrase || !privatekey) {
|
||||
const personfile = `${process.env.dirtown}/tribes/${tribeid}/person/itm/${alias}.json`;
|
||||
const persondata = fs.existsSync(personfile)
|
||||
? fs.readJsonSync(personfile)
|
||||
: {};
|
||||
if (persondata.length == 0) {
|
||||
return {
|
||||
status: 404,
|
||||
ref: "Pagans",
|
||||
msg: "persondoesnotexist",
|
||||
data: { alias, tribeid },
|
||||
};
|
||||
}
|
||||
person.email = persondata.recoveryauth.email;
|
||||
person.publickey = persondata.recoveryauth.publickey;
|
||||
person.privatekey = persondata.recoveryauth.privatekey;
|
||||
person.passphrase = persondata.recoveryauth.passphrase;
|
||||
} else {
|
||||
person.email = email;
|
||||
person.passphrase = passphrase;
|
||||
person.publickey = publickey;
|
||||
}
|
||||
console.log("person:", person);
|
||||
|
||||
//feedback.withemail = true;
|
||||
//feedback.email = email;
|
||||
//feedback.privatekey = privatekey;
|
||||
//feedback.passphrase = passphrase;
|
||||
const mailidentity = {
|
||||
subjecttpl: "Information pour l'alias: {{alias}}",
|
||||
htmltpl:
|
||||
"<h1>Votre identité {{alias}} via {{tribeid}}</h1><p>Passphrase:</p></p><p>{{{passphrase}}</p><p>Cle public:</p><p>{{{publickey}}</p><p>Cle privée</p><p>{{{privatekey}}</p>",
|
||||
texttpl:
|
||||
"Votre identité {{alias}}\nPassphrase:\n{{{passphrase}}\nCle public:\n{{{publickey}}\nCle privée\n{{{privatekey}}",
|
||||
filelist: [],
|
||||
};
|
||||
|
||||
const maildata = {
|
||||
To: person.email,
|
||||
subject: Mustache.render(mailidentity.subject, person),
|
||||
htmlpart: Mustache.render(mailidentity.htmltpl, person),
|
||||
textpart: Mustache.render(mailidentity.texttpl, person),
|
||||
filelist: [],
|
||||
};
|
||||
fs.outputFileSync(
|
||||
`${conf.dirtown}/tmp/${person.alias}_privatekey.txt`,
|
||||
person.privatekey,
|
||||
"utf8"
|
||||
);
|
||||
maildata.filelist.push({
|
||||
filename: "${person.alias}_privatekey.txt",
|
||||
pathfile: `${conf.dirtown}/tmp/${person.alias}_privatekey.txt`,
|
||||
});
|
||||
fs.outputFileSync(
|
||||
`${conf.dirtown}/tmp/${person.alias}_publickey.txt`,
|
||||
person.publickey,
|
||||
"utf8"
|
||||
);
|
||||
maildata.filelist.push({
|
||||
filename: "${person.alias}_publickey.txt",
|
||||
pathfile: `${conf.dirtown}/tmp/${person.alias}_publickey.txt`,
|
||||
});
|
||||
//fs.readJSONSync('${conf.dirapi}/api/')
|
||||
return Notifications.sendmail(maildata, tribeid);
|
||||
};
|
||||
|
||||
Pagans.authenticatedetachedSignature = async (
|
||||
alias,
|
||||
@ -185,6 +306,15 @@ Pagans.authenticatedetachedSignature = async (
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* todo recuperer tous les tokens et les distribuer à la town
|
||||
* @param {string} alias
|
||||
*/
|
||||
Pagans.deletealias = (alias) => {
|
||||
// check if alias is used in the blockchain
|
||||
// if not then delete itm pagan alias => this means that alias is now available for someone else
|
||||
};
|
||||
Pagans.deleteperson = (alias, tribeId) => {};
|
||||
Pagans.keyrecovery = (tribeid, email) => {
|
||||
glob
|
||||
.GlobSync(`${conf.dirtown}/tribes/${tribeId}/Person/*.json`)
|
||||
|
57
api/models/Trackings.js
Normal file
@ -0,0 +1,57 @@
|
||||
/**
|
||||
* Tracking management:
|
||||
*
|
||||
* without header:
|
||||
* https://dns.xx/trk/pathtofile?alias=anonymous&uuid=1b506f71-1bff-416c-9057-cb8b86296f60&src=btnregister&version=1&lg=fr
|
||||
*
|
||||
* with header
|
||||
* https://dns.xx/trk/pathtofile?src=btnregister&version=1
|
||||
*
|
||||
* where pathtofile is a ressource accessible from https://dns.xx/pathtofile
|
||||
*
|
||||
* We get :
|
||||
* alias: if athenticated from header else anonymous
|
||||
* uuid: a uuid v4 générate the first time a web page is open on a browser
|
||||
* src: source action that trig this get
|
||||
* version: can be an int, date or any version of the src
|
||||
* tm: optionnal is a timestamp of action when it is not immediate (offline app)
|
||||
*
|
||||
* html usage to track a loading page or email when a picture is load
|
||||
* using apxwebapp in /src/ we got:
|
||||
* <img src="static/img/photo.jpg" data-trksrckey="loadpage" data-version="1">
|
||||
*
|
||||
* using html + apx.js (or at least with header {xalias,xuuid,xlang})
|
||||
* <img lazysrc="trk/static/img/photo.jpg data-trksrckey="loadpage" data-version="1">
|
||||
*
|
||||
*
|
||||
* in js action:
|
||||
* <button></button> or
|
||||
* <a data-trksrc="linktoblabla" href='https:..'
|
||||
* onclick="apx.trackvisit("btnaction",1);actionfct();">
|
||||
* </a>
|
||||
* will hit an eventlistener
|
||||
* axios.get("https://dns.xx/trk/cdn/empty.json?alias=anonymous&uuid=1b506f71-1bff-416c-9057-cb8b86296f60&src=btnregister&version=1");
|
||||
*
|
||||
*
|
||||
* or if no js available (example:email or pdf document)
|
||||
* <img src="https://dns.xx/trk/static/img/photo.jpg?alias=anonymous&uuid=1b506f71-1bff-416c-9057-cb8b86296f60&srckey=loadpage&version=1" will hit a tracker
|
||||
*
|
||||
* <a href="https://dns.xx/trk/redirect?alias=anonymous&uuid=1b506f71-1bff-416c-9057-cb8b86296f60&srckey=loadpage&version=1&url=http://..." will hit a tracker then redirect to url></a> *
|
||||
*
|
||||
*
|
||||
* if you use apx.js :
|
||||
* in html add in <button>, <img>, <a> tag data-trksrc="srckey"
|
||||
* <img src="https://dns.xx/static/img/photo.jpg" data-trkversion="1" data-trksrckey="registerform">
|
||||
* <button data-trksrc="https://dns.xx/static/img/photo.jpg" data-trkversion="1" data-trksrckey="registerform">
|
||||
* in js call apx.track(srckey);
|
||||
*
|
||||
* Tracking log into tribe/logs/nginx/tribe_appname.trk.log
|
||||
* Src have to be manage in tribe/api/models/lg/src_en.json
|
||||
* {"srckey":{
|
||||
* "app":"presentation|app|apptest",
|
||||
* "title":"",
|
||||
* "description":""
|
||||
* }
|
||||
* }
|
||||
*
|
||||
*/
|
@ -15,6 +15,33 @@ const Checkjson = require( `./Checkjson.js`);
|
||||
/*
|
||||
tribeid manager
|
||||
|
||||
@TODO @STUDY
|
||||
|
||||
To add a tribe in dirtown/tribes with a mayor phil
|
||||
see man adduser and file reference call skelet directory to set an env for apxtrib in /home/tribename/
|
||||
accessible by tribename/password
|
||||
then add group group me to phil to allow phil to ate a symlink /dirtown/tribes/tribename => to /home/tribename
|
||||
|
||||
At each reboot run a process to analyse /api/routes and api/models whre only js can be exexuted are safe (only write data into /home/tribename, never outside)
|
||||
|
||||
1- Create a user in linux with $ sudo useradd smatchit
|
||||
2 => this create a user:group and a folder smatchit in /home/phil/dirtown/tribes/
|
||||
2 => add group smatchit to phil to allow phil to access file with a group accessright
|
||||
3 set a password if needed "$sudo passwd smatchit" (sm@tchit) to smatchit to make it available from ssh on port 22
|
||||
4
|
||||
4 to delete a user sudo userdel smatchit (this keep folder smatchit to remove folder smatchit => sudo userdel --remove smacthit)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/tribes/tribeid
|
||||
Manage a tribeid space
|
||||
* create
|
||||
|
@ -1,4 +1,5 @@
|
||||
{
|
||||
"validcheck":"Your data are valid",
|
||||
"typedoesnnotexistinschema":"This type in your propertie is not manage by Checkjson.js",
|
||||
"dataerrpropertie":"Check your data that not fit your schema rules propertie",
|
||||
"dataerrpropertiesrequired":"This propertie is required and not present in your data"
|
||||
|
6
api/models/lg/Checkjson_fr.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"validcheck":"Your data are valid",
|
||||
"typedoesnnotexistinschema":"This type in your propertie is not manage by Checkjson.js",
|
||||
"dataerrpropertie":"Check your data that not fit your schema rules propertie",
|
||||
"dataerrpropertiesrequired":"This propertie is required and not present in your data"
|
||||
}
|
9
api/models/lg/Notifications_fr.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"missingconf":"Il manque un smtp/sms valide pour {{tribe}} ou sur le serveur /conf.json",
|
||||
"missingdata":"Il manque des données obligatoire dans data {{#missingk}} {{.}} {{/missingk}}",
|
||||
"missingfile":"Le ou les fichiers suivants n'existent pas {{#missingfile}} {{.}} {{/missingfile}}",
|
||||
"errsendmail":"Une erreur s'est produite lors de l'envoie de l'email",
|
||||
"successfullsentemail":"Email correctement envoyé",
|
||||
"errsendsms":"Une erreur s'est produite lors de l'envoie du sms",
|
||||
"successfullsentsms":"Sms bien envoyé à {{To}}"
|
||||
}
|
13
api/models/lg/Odmdb_fr.json
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"alreadyexist": "Un object {{objectname}} avec la clé {{key}} existe déjà avec {{val}}",
|
||||
"doesnotexist": "L'object {{objectname}} avec la clé {{key}} ,'existe pas avec {{val}}",
|
||||
"getschema": "Schema {{{conf.name}}}",
|
||||
"schemanotfound": "Schema introuvable dans {{{schemaPath}}}",
|
||||
"pathnamedoesnotexist": "Le repertoire n'existe pas {{{indexpath}}}",
|
||||
"objectfiledoesnotexist": "Le fichier n'exuiste pas {{{objectpath}}}",
|
||||
"cudsuccessfull": "Mise à jour effectuée avec succés",
|
||||
"misssingprimarykey": "Il manque une clé primaire apxid pour stocker et identifier les objects",
|
||||
"unconsistencyapxidx": "L'index {{name}} doit contenir en objkey au moins {{apxid}} car keyval n'est pas unique",
|
||||
"profilnotallow": "Vous n'avez pas le profil de {{profils}}, cette action n'est pas authorisée",
|
||||
"successreindex": "Objet reindexé à partir des items, vos index sont à jour"
|
||||
}
|
@ -1,5 +1,8 @@
|
||||
{
|
||||
"successfullcreate": "Alias creation for {{alias}} successfull. {{#withemail}} An email was sent to {{email}}, if you do not receive it, please download your keys before living this page.{{/withemail}}",
|
||||
"successfulluppdate": "Your alias as a Person is now update into {{tribe}}",
|
||||
"tribedoesnotexist": "Your tribe {{tribe}} does not exist in this town"
|
||||
"aliasexist":"This alias {{alias]} exist",
|
||||
"aliasdoesnotexist":"This alias {{alias}} does not exist ",
|
||||
"personexist":"This person {{alias}} exist for {{tribeid}}",
|
||||
"successfullcreate": "This identity {{alias}} creation was successfull. {{#withemail}} An email was sent to {{email}}, if you do not receive it, please download your keys before living this page.{{/withemail}}",
|
||||
"successfulluppdate": "Your alias as a Person is now update into {{tribeid}}",
|
||||
"tribedoesnotexist": "Your tribe {{tribeid}} does not exist in this town"
|
||||
}
|
||||
|
@ -1,41 +1,13 @@
|
||||
{
|
||||
"ERRcritical": "Erreur critique",
|
||||
"loginAlreadyExist": "Ce login exist déjà",
|
||||
"emailAlreadyExist":"Cet email exist déjà",
|
||||
"failtoWritefs":"Impossible d'ecrire sur le serveur",
|
||||
"successfullCreate": "Création réussit",
|
||||
"successfullDelete": "Mise à jour effectuée",
|
||||
"serverNeedAuthentification":"Ce serveur a besoin d'une authentification",
|
||||
"forbiddenAccess":"Accès interdit",
|
||||
"userNotAllowtoCreate":"Pas d'autorisation de creation",
|
||||
"userNotAllowtoUpdate":"Pas d'autorisatiuon de mise à jour",
|
||||
"userNotAllowtoDelet":"Pas d'autorisation de suppression",
|
||||
"uuidNotFound":"Le paîen {{uuid}} n'existe pas dans la tribu {{tribeName}}",
|
||||
"useremailNotfound":"Email introuvable",
|
||||
"loginDoesNotExist":" Login introuvable",
|
||||
"checkCredentials":" Vérifier vos parametres d'accès"
|
||||
"wrongPassword":"Vérifier votre mot de passe",
|
||||
"invalidData":"Vérifier vos données",
|
||||
"pswToosimple":"Votre mot de passe est trop simple, doit contenir au moins 8 caractères avec des lettres majusculmes, minuscules des nombres et au moins un caractere special @! ...",
|
||||
"ERRemail":"Vérifier votre email",
|
||||
"ERRnewnewbisdiff":"Les 2 mots de passe ne sont pas identique",
|
||||
"uuiddesc":"Identifiant",
|
||||
"uuiddesclong":"Identifiant unique au format UUID.v4()",
|
||||
"uuidinfo":"<p> L'usage d'UUID v4 permet de générer un code unique sans centralisation, car il est basé sur un timestamp et une clé crypto ce qui donne un code du type 7d8291c0-e137-11e8-9f7b-1dc8e57bed33 </p>",
|
||||
"logindesc":"login",
|
||||
"logininfo":"<p>Le login doit être unique sur une instance d'apxtrib.</p><p> Pour échanger en dehors d'une instance apxtrib on utilise la clé public du user ou pour un humain login@trib.town§.nation.xx avec le nom du domaine qui heberge l'instance</p><p> Ou encore login@domain.xx tout domain.xx utilisé pour heberger un espace web client /tribeid/www/</p>",
|
||||
"biographydesc":"Vous en quelques mots",
|
||||
"publickeyinfo":"<p>Cette clé est générée par votre navigateur, garder précisuesement votre clé privée que seule vous connaissez. En cas de perte de cette clé tous vos actifs seront perdus.</p><p>Cette méthode nous permet de vous garantir un contrôle total décentralisé.</p>",
|
||||
"imgavatardesc":"Changer votren avatar",
|
||||
"imgavatarinfo":"Pour un meilleur rendu, une mage carré de 128pc en foat jpg",
|
||||
"emaildesc":"Email",
|
||||
"telephonedesc":"Tel",
|
||||
"familyNamedesc":"Nom",
|
||||
"givenNamedesc":"Prénom",
|
||||
"additionalNamedesc":"Pseudo",
|
||||
"additionalNamesinfo":"<p>Nom avec lequel vous souhaitez qu'on vous reconnaisse sur l'instance de l'apxtrib </p><p>Attention ce nom n'est unique que sur une instance d'apxtrib. Un même speudo peut-être utilisé sur un autre serveur pour garantir l'identité vérifié pseudo@ domaine de rattachement.</p>",
|
||||
"dtcreatedesc":"Date de creation",
|
||||
"dtupdatedesc":"Dernière mise à jour",
|
||||
"dtlastlogindesc":"Dernier accès au login",
|
||||
"accessrightsdesc":"Vos droits d'accès"
|
||||
}
|
||||
"aliasexist": "Cet alias {{data.alias}} existe",
|
||||
"emailerr": "Verifier votre email",
|
||||
"aliasorprivkeytooshort": "Vérifiez votre alias et votre clé privée",
|
||||
"aliasdoesnotexist": "Cet alias {{data.alias}} n'existe pas",
|
||||
"personexist": "Cette personne {{data.alias}} existe pour {{data.tribeid}}",
|
||||
"persondoesnotexist": "Cette personne {{data.alias}} n'existe pas pour {{data.tribeid}}",
|
||||
"successfullcreate": "La création de cette identité {{data.alias}} a été un succès. {{#data.withemail}} Un email a été envoyé à {{data.email}}, si vous ne le recevez pas, veuillez télécharger vos clés avant de quitter cette page.{{/data.withemail}}",
|
||||
"successfulcreatewithoutemail": "La creation de data.alias}} a été un succès. Aucun email ,'a été envoyé, verifier bien que vos clés sont bien sauvegardé de votre coté",
|
||||
"successfulluppdate": "Votre alias en tant que Personne est maintenant mis à jour dans {{data.tribeid}}",
|
||||
"errcreate": "Desolé, un probléme inconnu empeche la creation",
|
||||
"logout": "Votre token a été supprimé du server"
|
||||
}
|
||||
|
3
api/models/lg/Tribes_fr.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"actionmissing":"L'action {{data.action}} n'existe pas pour la tribut {{data.tribe}}."
|
||||
}
|
@ -1,7 +1,8 @@
|
||||
{
|
||||
"errrequest": "Backend seems not available",
|
||||
"missingheader": "Some header miss to have a valid request: {{#data}} {{.}} {{/data}}",
|
||||
"tribeiddoesnotexist": "Header xtribe: {{data.xtribe}} does not exist in this town",
|
||||
"tribeiddoesnotexist": "Header xtribe: {{data.xtribe}} does not exist in this town you cannot access",
|
||||
"authenticated": "Your alias{{{data.xalias}}} is authenticated",
|
||||
"notauthenticated": "Your alias: {{data.xalias}} is not authenticated {{^data.aliasexists}} and this alias does not exist !{{/data.aliasexists}}",
|
||||
"forbiddenAccessright": "Pagan {{data.xalias}} has not access right to act {{data.action}} onto object {{data.object}} for tribe {{mor.xworkon}}"
|
||||
"forbiddenAccessright": "Alias {{data.xalias}} has not access right to act {{data.action}} onto object {{data.object}} for tribe {{mor.xworkon}}"
|
||||
}
|
10
api/models/lg/middlewares_fr.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"errrequest": "Le serveur ne semble pas répondre",
|
||||
"unconsistentpgp": "Vos clés ne sont pas conforme {{err}}",
|
||||
"missingheader": "Certains en-têtes manquent pour avoir une requête valide : {{#data}} {{.}} {{/data}}",
|
||||
"tribeiddoesnotexist": "L'en-tête xtribe : {{data.xtribe}} n'existe pas dans cette ville, vous ne pouvez pas y accéder",
|
||||
"authenticated": "Votre alias {{{data.xalias}}} est authentifié",
|
||||
"notauthenticated": "Votre alias : {{data.xalias}} n'est pas authentifié {{^data.aliasexists}} et cet alias n'existe pas !{{/data.aliasexists}}",
|
||||
"forbiddenAccessright": "L'alias {{data.xalias}} n'a pas le droit d'agir {{data.action}} sur l'objet {{data.object}} pour la tribu {{mor.xworkon}}",
|
||||
"signaturefailled": "Desolé votre signature n'est pas valide pour cet alias."
|
||||
}
|
@ -3,6 +3,7 @@ Unit testing
|
||||
*/
|
||||
const assert = require("assert");
|
||||
const Checkjson = require("../Checkjson.js");
|
||||
const conf = require(`${process.env.dirtown}/conf.json`);
|
||||
|
||||
const ut = { name: "Checkjson" };
|
||||
|
||||
@ -17,115 +18,120 @@ const schema = {
|
||||
},
|
||||
};
|
||||
const testproperties = [
|
||||
{
|
||||
name: "test0",
|
||||
data: { totest: true },
|
||||
properties: { totest: { type: "boolean" } },
|
||||
status: 200
|
||||
},
|
||||
{
|
||||
name: "test0",
|
||||
data: { totest: true },
|
||||
properties: { totest: { type: "boolean" } },
|
||||
status: 200,
|
||||
},
|
||||
{
|
||||
name: "test1",
|
||||
data: { totest: "blabla" },
|
||||
properties: { totest: { type: "string" } },
|
||||
status: 200
|
||||
status: 200,
|
||||
},
|
||||
{
|
||||
name: "test2",
|
||||
data: { totest: 123 },
|
||||
properties: { totest: { type: "string" } },
|
||||
status: 417
|
||||
status: 417,
|
||||
},
|
||||
{
|
||||
name: "test3",
|
||||
data: { totest: 123.13 },
|
||||
properties: { totest: { type: "integer" } },
|
||||
status: 417
|
||||
status: 417,
|
||||
},
|
||||
{
|
||||
name: "test4",
|
||||
data: { totest: 123 },
|
||||
properties: { totest: { type: "number" } },
|
||||
status: 200
|
||||
status: 200,
|
||||
},
|
||||
{
|
||||
name: "test5",
|
||||
data: { totest: 12312 },
|
||||
properties: { totest: { type: "number" } },
|
||||
status: 200
|
||||
status: 200,
|
||||
},
|
||||
{
|
||||
name: "test6",
|
||||
data: { totest: 12.313 },
|
||||
properties: { totest: { type: "float" } },
|
||||
status: 200
|
||||
status: 200,
|
||||
},
|
||||
{
|
||||
name: "test7",
|
||||
data: { totest: "blablab sfde" },
|
||||
data: { totest: "blablab sfde" },
|
||||
properties: { totest: { type: "string", minLength: 1111 } },
|
||||
status: 417
|
||||
status: 417,
|
||||
},
|
||||
{
|
||||
name: "test8",
|
||||
data: { totest: "blablab sfde" },
|
||||
properties: { totest: { type: "string", minLength: 4, maxLength: 128} },
|
||||
status: 200
|
||||
data: { totest: "blablab sfde" },
|
||||
properties: { totest: { type: "string", minLength: 4, maxLength: 128 } },
|
||||
status: 200,
|
||||
},
|
||||
{
|
||||
name: "test9",
|
||||
data: { totest: 12 },
|
||||
properties: { totest: { type: "integer", multipleOf:3} },
|
||||
status: 200
|
||||
data: { totest: 12 },
|
||||
properties: { totest: { type: "integer", multipleOf: 3 } },
|
||||
status: 200,
|
||||
},
|
||||
{
|
||||
name: "test10",
|
||||
data: { totest: 9 },
|
||||
properties: { totest: { type: "number", minimum:-10, exclusiveMaximum:10} },
|
||||
status: 200
|
||||
data: { totest: 9 },
|
||||
properties: {
|
||||
totest: { type: "number", minimum: -10, exclusiveMaximum: 10 },
|
||||
},
|
||||
status: 200,
|
||||
},
|
||||
{
|
||||
name: "test11",
|
||||
data: { totest: 10 },
|
||||
properties: { totest: { type: "number", minimum:-10, exclusiveMaximum:10} },
|
||||
status: 417
|
||||
data: { totest: 10 },
|
||||
properties: {
|
||||
totest: { type: "number", minimum: -10, exclusiveMaximum: 10 },
|
||||
},
|
||||
status: 417,
|
||||
},
|
||||
{
|
||||
name: "test12",
|
||||
data: { totest: "gfhrtabcdgfr" },
|
||||
properties: { totest: { type: "string", pattern:/.*abc.*/} },
|
||||
status: 200
|
||||
data: { totest: "gfhrtabcdgfr" },
|
||||
properties: { totest: { type: "string", pattern: /.*abc.*/ } },
|
||||
status: 200,
|
||||
},
|
||||
{
|
||||
name: "test13",
|
||||
data: { totest: "toto@google.com" },
|
||||
properties: { totest: { type: "string", format:"email"} },
|
||||
status: 200
|
||||
data: { totest: "toto@google.com" },
|
||||
properties: { totest: { type: "string", format: "email" } },
|
||||
status: 200,
|
||||
},
|
||||
{
|
||||
name: "test14",
|
||||
data: { totest: "Aze123@0" },
|
||||
properties: { totest: { type: "string", format:"password"} },
|
||||
status: 200
|
||||
data: { totest: "Aze123@0" },
|
||||
properties: { totest: { type: "string", format: "password" } },
|
||||
status: 200,
|
||||
},
|
||||
{
|
||||
name: "test15",
|
||||
data: { totest: "value1" },
|
||||
properties: { totest: { type: "string", enum:["value1","value2","value3"]} },
|
||||
status: 200
|
||||
data: { totest: "value1" },
|
||||
properties: {
|
||||
totest: { type: "string", enum: ["value1", "value2", "value3"] },
|
||||
},
|
||||
status: 200,
|
||||
},
|
||||
{
|
||||
name: "test16",
|
||||
data: { totest: ["t1","t2"] },
|
||||
properties: { totest: { type: ["string", "number"] }},
|
||||
status: 417
|
||||
}
|
||||
,
|
||||
data: { totest: ["t1", "t2"] },
|
||||
properties: { totest: { type: ["string", "number"] } },
|
||||
status: 417,
|
||||
},
|
||||
{
|
||||
name: "test17",
|
||||
data: { totest: 12 },
|
||||
properties: { totest: { type: ["string", "number"] }},
|
||||
status: 200
|
||||
}
|
||||
properties: { totest: { type: ["string", "number"] } },
|
||||
status: 200,
|
||||
},
|
||||
];
|
||||
|
||||
ut.testproperties = (options) => {
|
||||
@ -134,10 +140,10 @@ ut.testproperties = (options) => {
|
||||
schema.properties = t.properties;
|
||||
const res = Checkjson.schema.data(schema, t.data);
|
||||
if (res.status != t.status) {
|
||||
msg = (msg == "") ? "Unconsistent testproperties() name list: " : `${msg},`;
|
||||
msg = msg == "" ? "Unconsistent testproperties() name list: " : `${msg},`;
|
||||
if (options.verbose) {
|
||||
console.log(t)
|
||||
console.log(res);
|
||||
console.log(t);
|
||||
console.log(res);
|
||||
}
|
||||
msg += res.err.map((e) => ` ${t.name} ${e.info}`);
|
||||
}
|
||||
|
@ -2,71 +2,42 @@
|
||||
Unit testing
|
||||
*/
|
||||
const assert = require("assert");
|
||||
const fs=require('fs-extra');
|
||||
const path= require('path');
|
||||
const fs = require("fs-extra");
|
||||
const path = require("path");
|
||||
const Odmdb = require("../Odmdb.js");
|
||||
const {generemdp} = require('../../nationchains/socialworld/contracts/toolsbox.js');
|
||||
const { generemdp } = require("../toolsbox.js");
|
||||
const conf = require(`${process.env.dirtown}/conf.json`);
|
||||
|
||||
const ut = { name: "Odmdb" };
|
||||
/*
|
||||
We test only search and indexation here
|
||||
Create Update Read and Delete are unit testing with specificities of each Object.
|
||||
|
||||
To do that we create in tmp a dummy data folder for a dummy schema object
|
||||
Test crud process for any object
|
||||
*/
|
||||
const schema = {
|
||||
$schema: "http://json-schema.org/schema#",
|
||||
title: "Dummy schema to test Checkjson.js",
|
||||
description: "Checkjson is use on server as well as into a browser",
|
||||
$comment: "We change schema type on the fly to simplify the test",
|
||||
type: "object",
|
||||
properties: {
|
||||
uuid: {
|
||||
type:"string",
|
||||
format:"uuid",
|
||||
default:"=uuid.v4()"
|
||||
},
|
||||
dtcreate:{
|
||||
type:"string",
|
||||
format:"datetime",
|
||||
default:"=date.now()"
|
||||
},
|
||||
tag:{
|
||||
type:"string",
|
||||
enum:["t1","t2","t3"],
|
||||
default:"t1"
|
||||
},
|
||||
info:{
|
||||
type:"string",
|
||||
minLength: 10,
|
||||
default:"=generemdp(255,'ABCDEFGHIJKLM 12340')"
|
||||
}
|
||||
},
|
||||
required:["uuid"],
|
||||
apxprimarykey:"uuid",
|
||||
apxuniquekey:["info"],
|
||||
apxsearchindex:{
|
||||
"uuid":{"list":[],"taginfo":['tag','info'],"all":""},
|
||||
"info":{"uuid":['uuid']}
|
||||
}
|
||||
};
|
||||
ut.crud = (objectPathname, itm, profils) => {
|
||||
//
|
||||
// test if exist
|
||||
// if not test create
|
||||
// test to read
|
||||
// test update
|
||||
// test delete
|
||||
const res = { status: 200, err: [] };
|
||||
return res;
|
||||
};
|
||||
|
||||
const obj={tag:"t1",info:"Lorem ipsum A"}
|
||||
const testvar={alias:"tutu", passphrase:"",privatekey:"", publickey:""}
|
||||
|
||||
ut.createanobject=(schema,obj)=>{
|
||||
const testitms=[
|
||||
{objectPathname:`${conf.dirapi}/nationchains/pagans`,
|
||||
itm:{alias:'toutou', publickey:}}
|
||||
]
|
||||
|
||||
const res={status:200,err:[]}
|
||||
return res
|
||||
}
|
||||
|
||||
ut.run = (options) => {
|
||||
const objectPath=path.resolve(__dirname,'../../tmp/testobjects');
|
||||
const schemaPath=path.resolve(__dirname,'../../tmp/testschema');
|
||||
if (!fs.existsSync(objectPath)) fs.ensureDirSync(objectPath);
|
||||
if (!fs.existsSync(schemaPath)) fs.ensureDirSync(schemaPath);
|
||||
const createenvobj=Odmdb.setObject(schemaPath,objectPath,"objtest",schema,{},"en");
|
||||
assert.deepEqual(createenvobj,{status:200},JSON.stringify(createenvobj));
|
||||
const checkschema= Odmdb.schema(schemaPath,"objtest",true)
|
||||
assert.deepEqual(checkschema.status,200,JSON.stringify(checkschema))
|
||||
};
|
||||
module.exports = ut;
|
||||
|
||||
ut.run = (options) => {
|
||||
let msg=""
|
||||
testitms.forEach(i=>{
|
||||
ut.crud(i)
|
||||
//si erreur add msg+++
|
||||
})
|
||||
assert.deepEqual(msg, "", msg);
|
||||
};
|
||||
module.exports = ut;
|
||||
|
@ -6,7 +6,6 @@ const Nations = require( '../models/Nations.js' );
|
||||
// Middlewares
|
||||
const checkHeaders = require( '../middlewares/checkHeaders' );
|
||||
const isAuthenticated = require( '../middlewares/isAuthenticated' );
|
||||
const hasAccessrighton = require( '../middlewares/hasAccessrighton' );
|
||||
const router = express.Router();
|
||||
|
||||
/*
|
||||
|
@ -7,32 +7,98 @@ const Odmdb = require("../models/Odmdb.js");
|
||||
// Middlewares
|
||||
const checkHeaders = require("../middlewares/checkHeaders");
|
||||
const isAuthenticated = require("../middlewares/isAuthenticated");
|
||||
const hasAccessrighton = require("../middlewares/hasAccessrighton");
|
||||
const router = express.Router();
|
||||
|
||||
/**
|
||||
* @api {get} /odmdb/rebuildidx/:objectname
|
||||
* @apiName Rebuild all index for an object
|
||||
* @apiGroup Odmdb
|
||||
*
|
||||
* @apiUse apxHeader
|
||||
* @objectname {string} Mandatory
|
||||
*
|
||||
* @apiError (404) {string} status the file does not exist
|
||||
* @apiError (404) {string} ref objectmodel to get in the right language
|
||||
* @apiError (404) {string} msg key to get template from objectmodel
|
||||
* @apiError (404) {object} data use to render lg/objectmodel_lg.json
|
||||
*
|
||||
* @apiSuccess (200) {object} data contains indexfile requested
|
||||
*
|
||||
*/
|
||||
router.get(
|
||||
"/rebuildidx/:objectname",
|
||||
checkHeaders,
|
||||
isAuthenticated,
|
||||
(req, res) => {
|
||||
console.log("reindex");
|
||||
// check validity and accessright
|
||||
const objectPathname = conf.api.nationObjects.includes(
|
||||
req.params.objectname
|
||||
)
|
||||
? `${conf.dirapi}/nationchains/${req.params.objectname}`
|
||||
: `${conf.dirtown}/tribes/${req.session.header.xtribe}/${req.params.objectname}`;
|
||||
//console.log(objectPathname);
|
||||
if (!fs.existsSync(objectPathname)) {
|
||||
res.status(404).json({
|
||||
status: 404,
|
||||
ref: "Odmdb",
|
||||
msg: "pathnamedoesnotexist",
|
||||
data: { indexpath: objectPathname },
|
||||
});
|
||||
return false;
|
||||
}
|
||||
if (
|
||||
conf.api.nationObjects.includes(req.params.objectname) &&
|
||||
!req.session.header.xprofils.includes("mayor")
|
||||
) {
|
||||
res.status(403).json({
|
||||
status: 403,
|
||||
ref: "Odmdb",
|
||||
msg: "profilnotallow",
|
||||
data: { profils: "mayor" },
|
||||
});
|
||||
return false;
|
||||
}
|
||||
if (
|
||||
!conf.api.nationObjects.includes(req.params.objectname) &&
|
||||
!req.session.header.xprofils.includes("druid")
|
||||
) {
|
||||
res.status(403).json({
|
||||
status: 403,
|
||||
ref: "Odmdb",
|
||||
msg: "profilnotallow",
|
||||
data: { profils: "druid" },
|
||||
});
|
||||
return false;
|
||||
}
|
||||
const reindex = Odmdb.idxfromitm(objectPathname, "I", {}, {}, [], {});
|
||||
res.status(reindex.status).json(reindex);
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* @api {get} /odmdb/idx/:indexname
|
||||
* @apiName Get index file for an object
|
||||
* @apiGroup Odmdb
|
||||
*
|
||||
* @apiUse apxHeader
|
||||
* @objectname {string} Mandatory
|
||||
* @apiParam {String} indexname Mandatory if in conf.nationObjects then file is into nationchains/ else in /nationchains/tribes/xtribe/objectname/idx/indexname indexname contains the ObjectName .*_ (before the first _)
|
||||
*
|
||||
* @apiError (404) {string} status the file does not exist
|
||||
* @apiError (404) {string} ref objectmodel to get in the right language
|
||||
* @apiError (404) {string} msg key to get template from objectmodel
|
||||
* @apiError (404) {object} data use to render lg/objectmodel_lg.json
|
||||
*
|
||||
* @apiSuccess (200) {object} data contains indexfile requested
|
||||
*
|
||||
*/
|
||||
router.get(
|
||||
"/:objectname/idx/:indexname",
|
||||
checkHeaders,
|
||||
isAuthenticated,
|
||||
(req, res) => {
|
||||
/**
|
||||
* @api {get} /odmdb/idx/:indexname
|
||||
* @apiName Get index file for an object
|
||||
* @apiGroup Odmdb
|
||||
*
|
||||
* @apiUse apxHeader
|
||||
* @objectname {string} Mandatory
|
||||
* @apiParam {String} indexname Mandatory if in conf.nationObjects then file is into nationchains/ else in /nationchains/tribes/xtribe/objectname/idx/indexname indexname contains the ObjectName .*_ (before the first _)
|
||||
*
|
||||
* @apiError (404) {string} status the file does not exist
|
||||
* @apiError (404) {string} ref objectmodel to get in the right language
|
||||
* @apiError (404) {string} msg key to get template from objectmodel
|
||||
* @apiError (404) {object} data use to render lg/objectmodel_lg.json
|
||||
*
|
||||
* @apiSuccess (200) {object} data contains indexfile requested
|
||||
*
|
||||
*/
|
||||
console.log("pzasse");
|
||||
console.log("passe");
|
||||
// indexname = objectname_key_value.json
|
||||
let objectLocation = "../../nationchains/";
|
||||
if (!conf.api.nationObjects.includes(req.params.objectname)) {
|
||||
@ -51,29 +117,29 @@ router.get(
|
||||
}
|
||||
}
|
||||
);
|
||||
/**
|
||||
* @api {get} /odmdb/itm/:objectname/:primaryindex
|
||||
* @apiName Get index file for an object
|
||||
* @apiGroup Odmdb
|
||||
*
|
||||
* @apiUse apxHeader
|
||||
*
|
||||
* @apiParam {String} objectname name Mandatory if in conf.nationObjects then file is into nationchains/ else in /nationchains/tribes/xtribe/objectname
|
||||
* @apiParam {String} primaryindex the unique id where item is store
|
||||
* @apiError (404) {string} status the file does not exist
|
||||
* @apiError (404) {string} ref objectmodel to get in the right language
|
||||
* @apiError (404) {string} msg key to get template from objectmodel
|
||||
* @apiError (404) {object} data use to render lg/objectmodel_lg.json
|
||||
*
|
||||
* @apiSuccess (200) {object} data contains indexfile requested
|
||||
*
|
||||
*/
|
||||
// indexname = objectname_key_value.json
|
||||
router.get(
|
||||
"/:objectname/itm/:primaryindex",
|
||||
checkHeaders,
|
||||
isAuthenticated,
|
||||
(req, res) => {
|
||||
/**
|
||||
* @api {get} /odmdb/item/:objectname/:primaryindex
|
||||
* @apiName Get index file for an object
|
||||
* @apiGroup Odmdb
|
||||
*
|
||||
* @apiUse apxHeader
|
||||
*
|
||||
* @apiParam {String} objectname name Mandatory if in conf.nationObjects then file is into nationchains/ else in /nationchains/tribes/xtribe/objectname
|
||||
* @apiParam {String} primaryindex the unique id where item is store
|
||||
* @apiError (404) {string} status the file does not exist
|
||||
* @apiError (404) {string} ref objectmodel to get in the right language
|
||||
* @apiError (404) {string} msg key to get template from objectmodel
|
||||
* @apiError (404) {object} data use to render lg/objectmodel_lg.json
|
||||
*
|
||||
* @apiSuccess (200) {object} data contains indexfile requested
|
||||
*
|
||||
*/
|
||||
// indexname = objectname_key_value.json
|
||||
const objectName = req.params.objectname;
|
||||
const objectId = req.params.primaryindex;
|
||||
let objectLocation = "../../nationchains/";
|
||||
@ -97,7 +163,8 @@ router.get(
|
||||
);
|
||||
|
||||
router.post(":objectname/itm", checkHeaders, isAuthenticated, (req, res) => {
|
||||
// Create an item of an object
|
||||
// Create an item of an object with no specificities
|
||||
// if specificities then create a route / model that import odmdb
|
||||
});
|
||||
router.get(
|
||||
"/searchitems/:objectname/:question",
|
||||
@ -126,24 +193,24 @@ router.get(
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* @api {get} /odmdb/schema/:objectname
|
||||
* @apiName GetSchema
|
||||
* @apiGroup Odmdb
|
||||
*
|
||||
* @apiUse apxHeader
|
||||
*
|
||||
* @apiParam {String} objectname Mandatory if headers.xworkon == nationchains then into ./nationchains/ else into ./tribes/xworkon/
|
||||
*
|
||||
* @apiError (404) {string} status a key word to understand not found schema
|
||||
* @apiError (404) {string} ref objectmodel to get in the right language
|
||||
* @apiError (404) {string} msg key to get template from objectmodel
|
||||
* @apiError (404) {object} data use to render lg/objectmodel_lg.json
|
||||
*
|
||||
* @apiSuccess (200) {object} data contains schema requested
|
||||
*
|
||||
*/
|
||||
router.get("schema/:objectname", checkHeaders, isAuthenticated, (req, res) => {
|
||||
/**
|
||||
* @api {get} /odmdb/schema/:objectname
|
||||
* @apiName GetSchema
|
||||
* @apiGroup Odmdb
|
||||
*
|
||||
* @apiUse apxHeader
|
||||
*
|
||||
* @apiParam {String} objectname Mandatory if headers.xworkon == nationchains then into ./nationchains/ else into ./tribes/xworkon/
|
||||
*
|
||||
* @apiError (404) {string} status a key word to understand not found schema
|
||||
* @apiError (404) {string} ref objectmodel to get in the right language
|
||||
* @apiError (404) {string} msg key to get template from objectmodel
|
||||
* @apiError (404) {object} data use to render lg/objectmodel_lg.json
|
||||
*
|
||||
* @apiSuccess (200) {object} data contains schema requested
|
||||
*
|
||||
*/
|
||||
const fullpath = path.resolve(
|
||||
`${__dirname}/tribes/${req.session.header.xworkon}/schema/${req.params.pathobjectname}.json`
|
||||
);
|
||||
|
@ -1,210 +1,226 @@
|
||||
const express = require("express");
|
||||
const fs = require("fs-extra");
|
||||
const path = require("path");
|
||||
|
||||
// Classes
|
||||
const Pagans = require("../models/Pagans.js");
|
||||
const Notifications = require("../models/Notifications.js");
|
||||
|
||||
// Middlewares
|
||||
const checkHeaders = require("../middlewares/checkHeaders");
|
||||
const isAuthenticated = require("../middlewares/isAuthenticated");
|
||||
const hasAccessrighton = require("../middlewares/hasAccessrighton");
|
||||
|
||||
const router = express.Router();
|
||||
/*
|
||||
models/Pagans.js
|
||||
Managed:
|
||||
/data/tribee/client-Id/users/uuid.json
|
||||
/searchindex/emails.json {email:uuid}
|
||||
/login.json {login:uuid}
|
||||
/uids.json {uuid;[[
|
||||
login,
|
||||
email,
|
||||
encrypted psw,
|
||||
accessrights]}
|
||||
/**
|
||||
* /api/models/Pagans.js
|
||||
*
|
||||
* Managed:
|
||||
|
||||
ACCESSRIGHTS = {
|
||||
app:{"tribeid:appname":"profil"},
|
||||
data:{"tribeid":{object:"CRUDO"}}
|
||||
}
|
||||
ACCESSRIGHTS is store into the token and is load into req.session.header.accessrights by hasAccessrighton() middleware
|
||||
|
||||
appname is a website space object /sitewebsrc/appname
|
||||
website live is strored into /dist source in /src
|
||||
|
||||
This can be managed by maildigitcreator or not.
|
||||
apxtrib/sitewebs/webapp is the webinterface of apxtrib
|
||||
|
||||
profil: admin / manager / user are key word to give specific access to data into model. Any kind of other profil can exist. It is usefull to manage specific menu in an app.
|
||||
It is also possible to authorize update a field's object depending of rule into dataManagement/object/
|
||||
{ field:X
|
||||
nouserupdate: "!(['admin','manager'].includes(contexte.profil))",
|
||||
}
|
||||
|
||||
data allow a user to access tribeid with Create Read Update Delete Own (CRUDO) on each object of a tribeid independantly of any app.
|
||||
|
||||
Create allow to create a new object respecting rules defined into /referentials/dataManagement/object/name.json
|
||||
Update idem
|
||||
Delete idem
|
||||
Owner means it can be Write/Delete if field OWNER contain the UUID that try to act on this object. Usefull to allow someone to fully manage its objects.
|
||||
|
||||
*/
|
||||
/**
|
||||
* @api {get} /pagans/alias/:alias
|
||||
* @apiName Is register check xalias and xhash
|
||||
* @apiGroup Pagans
|
||||
* @param {string} alias a alias that exist or not
|
||||
* @apiSuccess (200) {object} {ref:"pagans",msg:"aliasexist",data: { alias, publicKey } }
|
||||
* @apiError (404) {object} {ref:"pagans",msg:"aliasdoesnotexist",data: { alias} }
|
||||
*
|
||||
**/
|
||||
router.get("/alias/:alias", (req, res) => {
|
||||
/**
|
||||
* @api {get} /pagans/alias/:alias
|
||||
* @apiName Is register check xalias and xhash
|
||||
* @apiGroup Pagans
|
||||
* @param {string} alias a alias that exist or not
|
||||
* @apiSuccess (200) {object} {ref:"pagans",msg:"aliasexist",data: { alias, publicKey } }
|
||||
* @apiError (404) {object} {ref:"pagans",msg:"aliasdoesnotexist",data: { alias} }
|
||||
*
|
||||
**/
|
||||
res.send(Pagans.getalias(req.params.alias));
|
||||
const getalias = Pagans.getalias(req.params.alias);
|
||||
res.status(getalias.status).send(getalias);
|
||||
});
|
||||
router.get("/person/:alias", checkHeaders, isAuthenticated, (req, res) => {
|
||||
/**
|
||||
* @api {get} /pagans/person:alias
|
||||
* @apiName Is register check xalias and xhash
|
||||
* @apiGroup Pagans
|
||||
* @apiUse apxHeader
|
||||
* @param {string} alias that exist
|
||||
* @param {string} tribeId that exist with a person alias
|
||||
* @apiSuccess (200) {ref:"pagans",msg:"personexist",data: { person } }
|
||||
* @apiError (404) {ref:"pagans",msg:"persondoesnotexist",data: { person } }
|
||||
*
|
||||
* @todo check accessright for req.session.header.xalias to see if jhe can get person data
|
||||
* if req.param.alias == req.session.header.xalias => Owner
|
||||
* else need accessright to on person set at R
|
||||
* */
|
||||
res.send(Pagans.getperson(req.params.alias, req.session.header.xtribe));
|
||||
/**
|
||||
* @api {get} /pagans/logout
|
||||
* @apiName Remove token
|
||||
* @apiGroup Pagans
|
||||
*
|
||||
*/
|
||||
router.get("/logout", checkHeaders, isAuthenticated, (req, res) => {
|
||||
console.log(req.session.header);
|
||||
const logout = Pagans.logout(
|
||||
req.session.header.xalias,
|
||||
req.session.header.xtribe,
|
||||
req.session.header.xdays,
|
||||
req.session.header.xhash
|
||||
);
|
||||
res.status(logout.status).json(logout);
|
||||
});
|
||||
|
||||
/**
|
||||
* @api {get} /pagans/person:alias
|
||||
* @apiName Is register check xalias and xhash
|
||||
* @apiGroup Pagans
|
||||
* @apiUse apxHeader
|
||||
* @param {string} alias that exist
|
||||
* @param {string} tribeId that exist with a person alias
|
||||
* @apiSuccess (200) {ref:"pagans",msg:"personexist",data: { person } }
|
||||
* @apiError (404) {ref:"pagans",msg:"persondoesnotexist",data: { person } }
|
||||
*
|
||||
* @todo check accessright for req.session.header.xalias to see if jhe can get person data
|
||||
* if req.param.alias == req.session.header.xalias => Owner
|
||||
* else need accessright to on person set at R
|
||||
* */
|
||||
router.get("/person/:alias", checkHeaders, isAuthenticated, (req, res) => {
|
||||
const getperson = Pagans.getperson(
|
||||
req.session.header.xtribe,
|
||||
req.params.alias,
|
||||
{ xprofils: req.session.header.xprofils, xalias: req.session.header.xalias }
|
||||
);
|
||||
res.status(getperson.status).send(getperson);
|
||||
});
|
||||
|
||||
/**
|
||||
* @api {get} /pagans/isauth
|
||||
* @apiName Is register check xalias and xhash
|
||||
* @apiGroup Pagans
|
||||
* @apiUse apxHeader
|
||||
*
|
||||
* @apiError (400) {object} status missingheaders / xalias does not exist / signaturefailled
|
||||
* @apiError (401) {object} alias anonymous (not authenticated)
|
||||
* @apiError (404) {string} tribe does not exist
|
||||
*
|
||||
* @apiSuccess (200) {object} data contains indexfile requested
|
||||
*
|
||||
*/
|
||||
router.get("/isauth", checkHeaders, isAuthenticated, (req, res) => {
|
||||
/**
|
||||
* @api {get} /pagans/isauth
|
||||
* @apiName Is register check xalias and xhash
|
||||
* @apiGroup Pagans
|
||||
* @apiUse apxHeader
|
||||
*
|
||||
* @apiError (400) {object} status missingheaders / xalias does not exist / signaturefailled
|
||||
* @apiError (401) {object} alias anonymous (not authenticated)
|
||||
* @apiError (404) {string} tribe does not exist
|
||||
*
|
||||
* @apiSuccess (200) {object} data contains indexfile requested
|
||||
*
|
||||
*/
|
||||
res.send({
|
||||
res.status(200).send({
|
||||
status: 200,
|
||||
ref: "headers",
|
||||
msg: "authenticated",
|
||||
data: {
|
||||
xalias: req.session.header.xalias,
|
||||
xprofils: req.session.header.xprofils,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* @api {post} /pagans
|
||||
* @apiName Is register check xalias and xhash
|
||||
* @apiGroup Pagans
|
||||
* @apiUse apxHeader
|
||||
*
|
||||
* Create a pagan account from alias, publickey, if trusted recovery =>
|
||||
* Create a person in xtribe/person/xalias.json with profil.auth={email,privatekey, passphrase}
|
||||
* Middleware isAuthenticated check that:
|
||||
* - xhash is well signed from private key linked to the publickey of alias
|
||||
* - check that alias does not already exist (if yes then verifiedsigne would be false)
|
||||
* Need to wait next block chain to be sure that alias is register in the blokchain
|
||||
*/
|
||||
router.post("/", checkHeaders, isAuthenticated, (req, res) => {
|
||||
/**
|
||||
* @api {post} /pagans
|
||||
* @apiName Is register check xalias and xhash
|
||||
* @apiGroup Pagans
|
||||
* @apiUse apxHeader
|
||||
*
|
||||
* Create a pagan account from alias, publickey, if trusted recovery =>
|
||||
* Create a person in xtribe/person/xalias.json with profil.auth={email,privatekey, passphrase}
|
||||
* Middleware isAuthenticated check that:
|
||||
* - xhash is well signed from private key linked to the publickey of alias
|
||||
* - check that alias does not already exist (if yes then verifiedsigne would be false)
|
||||
* Need to wait next block chain to be sure that alias is register in the blokchain
|
||||
*/
|
||||
//console.log("pass ici", req.body);
|
||||
const feedback = { alias: req.body.alias, publickey: req.body.publickey };
|
||||
const newpagan = Pagans.create(req.body.alias, req.body.publickey);
|
||||
const objpagan = { alias: req.body.alias, publickey: req.body.publickey };
|
||||
const newpagan = Pagans.create(objpagan, {
|
||||
xalias: req.session.header.xalias,
|
||||
xprofils: req.session.header.xprofils,
|
||||
});
|
||||
if (newpagan.status == 200) {
|
||||
if (req.body.email) {
|
||||
feedback.withemail = true;
|
||||
feedback.email = req.body.email;
|
||||
feedback.privatekey = req.body.privatekey;
|
||||
feedback.passphrase = req.body.passphrase;
|
||||
Notifications.send({
|
||||
type: "email",
|
||||
from: "",
|
||||
dest: [req.body.email],
|
||||
tpl: "registeremail",
|
||||
tribe: req.session.header.xtribe,
|
||||
data: feedback,
|
||||
});
|
||||
const emailsent = Pagans.sendmailkey(
|
||||
req.body.alias,
|
||||
req.body.privatekey,
|
||||
req.session.header.xtribe,
|
||||
req.body.passphrase,
|
||||
req.body.publickey,
|
||||
req.body.email
|
||||
);
|
||||
}
|
||||
if (req.body.trustedtribe) {
|
||||
if (req.app.locals.tribeids.includes(req.body.trustedtribe)) {
|
||||
delete feedback.withemail;
|
||||
const persondata = { recovery: feedback };
|
||||
const persoup = Pagans.personupdate(req.body.alias, req.body.trustedtribe, persondata)
|
||||
res.status(persoup.status).json(persoup)
|
||||
/*res.send(
|
||||
Pagans.personupdate(req.body.alias, req.body.trustedtribe, persondata)
|
||||
);*/
|
||||
} else {
|
||||
res.status(404).json({
|
||||
status:404,
|
||||
ref: "Pagans",
|
||||
msg: "tribedoesnotexist",
|
||||
data: { tribe: req.body.trustedtribe },
|
||||
});
|
||||
/*res.send({
|
||||
status: 404,
|
||||
ref: "Pagans",
|
||||
msg: "tribedoesnotexist",
|
||||
data: { tribe: req.body.trustedtribe },
|
||||
});*/
|
||||
}
|
||||
} else {
|
||||
newpagan.data = feedback;
|
||||
const personup = Pagans.personupdate(
|
||||
req.body.alias,
|
||||
req.body.trustedtribe,
|
||||
{
|
||||
recoveryauth: {
|
||||
email: req.body.email,
|
||||
privatekey: req.body.privatekey,
|
||||
publickey: req.body.publickey,
|
||||
passphrase: req.body.passphrase,
|
||||
},
|
||||
}
|
||||
);
|
||||
if (personup.status !== 200)
|
||||
console.log("Warning no recovery registration", personup);
|
||||
}
|
||||
if (emailsent && emailsent.status != 200) {
|
||||
newpagan.msg = "successfulcreatewithoutemail";
|
||||
res.status(newpagan.status).json(newpagan);
|
||||
//res.send(newpagan);
|
||||
}
|
||||
} else {
|
||||
//error to create pagan
|
||||
res.send(newpagan);
|
||||
//error to create pagan certaily already exist
|
||||
res.status(newpagan.status).json(newpagan);
|
||||
}
|
||||
});
|
||||
router.put("/person", checkHeaders, isAuthenticated, (req, res) => {
|
||||
/**
|
||||
* @api {put} /pagans/person
|
||||
* @apiName Is register check xalias and xhash
|
||||
* @apiGroup Pagans
|
||||
* @apiUse apxHeader
|
||||
*
|
||||
* add/update a person = alias + tribe with specific accessright and specific schema link to tribe
|
||||
* @todo add tribe/schema/person.json
|
||||
*/
|
||||
/**
|
||||
* @api {post} /pagans/person
|
||||
* @apiName Is register check xalias and xhash
|
||||
* @apiGroup Pagans
|
||||
* @apiUse apxHeader
|
||||
*
|
||||
* add a person = alias + tribe with specific accessright and specific schema link to tribe
|
||||
* @todo add tribe/schema/person.json
|
||||
*/
|
||||
router.post("/person", checkHeaders, isAuthenticated, (req, res) => {
|
||||
//console.log(req.body);
|
||||
const persoup = Pagans.personupdate(req.body.alias, req.session.header.xtribe, req.body);
|
||||
const persoad = Pagans.personcreate(
|
||||
req.session.header.xtribe,
|
||||
req.body.alias,
|
||||
req.body,
|
||||
{ xprofils: req.session.header.xprofils, xalias: req.session.header.xalias }
|
||||
);
|
||||
res.status(persoad.status).json(persoad);
|
||||
});
|
||||
|
||||
/**
|
||||
* @api {put} /pagans/person
|
||||
* @apiName Is register check xalias and xhash
|
||||
* @apiGroup Pagans
|
||||
* @apiUse apxHeader
|
||||
*
|
||||
* update a person = alias + tribe with specific accessright and specific schema link to tribe
|
||||
* @todo add tribe/schema/person.json
|
||||
*/
|
||||
router.put("/person", checkHeaders, isAuthenticated, (req, res) => {
|
||||
//console.log(req.body);
|
||||
const persoup = Pagans.personupdate(
|
||||
req.session.header.xtribe,
|
||||
req.body.alias,
|
||||
req.body,
|
||||
{ xprofils: req.session.header.xprofils, xalias: req.session.header.xalias }
|
||||
);
|
||||
res.status(persoup.status).json(persoup);
|
||||
});
|
||||
router.delete("/:alias", checkHeaders, isAuthenticated, (req, res) => {
|
||||
/**
|
||||
* @api {delete} /pagans/:alias
|
||||
* @apiName Is register check xalias and xhash
|
||||
* @apiGroup Pagans
|
||||
* @apiUse apxHeader
|
||||
* */
|
||||
|
||||
/**
|
||||
* @api {delete} /pagans/alias/:alias
|
||||
* @apiName Is register check xalias and xhash
|
||||
* @apiGroup Pagans
|
||||
* @apiUse apxHeader
|
||||
* */
|
||||
router.delete("/alias/:alias", checkHeaders, isAuthenticated, (req, res) => {
|
||||
console.log(`DELETE pagans nationchains/pagans/${req.params.alias}.json`);
|
||||
const result = Pagans.delete(req.params.id, req.session.header);
|
||||
const result = Pagans.deletealias(req.params.id, req.session.header);
|
||||
res.status(result.status).send(result.data);
|
||||
});
|
||||
router.delete("/person/:alias", checkHeaders, isAuthenticated, (req, res) => {
|
||||
console.log(`DELETE pagans nationchains/pagans/${req.params.alias}.json`);
|
||||
const result = Pagans.deleteperson(req.params.id, req.session.header);
|
||||
res.status(result.status).send(result.data);
|
||||
});
|
||||
|
||||
/**
|
||||
* @api {get} /pagans/keyrecovery/tribe/email
|
||||
* @apiName apxtrib
|
||||
* @apiGroup Pagans
|
||||
*
|
||||
*
|
||||
*
|
||||
* @apiError (400) {object} status missingheaders / xalias does not exist / signaturefailled
|
||||
* @apiError (401) {object} alias anonymous (not authenticated)
|
||||
* @apiError (404) {string} tribe does not exist
|
||||
*
|
||||
* @apiSuccess (200) {object} data contains indexfile requested
|
||||
*
|
||||
*/
|
||||
router.get("/keyrecovery/:tribeid/:email", checkHeaders, (req, res) => {
|
||||
/**
|
||||
* @api {get} /pagans/keyrecovery/tribe/email
|
||||
* @apiName apxtrib
|
||||
* @apiGroup Pagans
|
||||
*
|
||||
*
|
||||
*
|
||||
* @apiError (400) {object} status missingheaders / xalias does not exist / signaturefailled
|
||||
* @apiError (401) {object} alias anonymous (not authenticated)
|
||||
* @apiError (404) {string} tribe does not exist
|
||||
*
|
||||
* @apiSuccess (200) {object} data contains indexfile requested
|
||||
*
|
||||
*/
|
||||
res.send(Pagans.keyrecovery(req.params.tribeId, req.params.email));
|
||||
});
|
||||
module.exports = router;
|
||||
|
@ -7,7 +7,6 @@ const Notifications = require("../models/Notifications.js");
|
||||
// Middlewares
|
||||
const checkHeaders = require("../middlewares/checkHeaders");
|
||||
const isAuthenticated = require("../middlewares/isAuthenticated");
|
||||
const hasAccessrighton = require("../middlewares/hasAccessrighton");
|
||||
const router = express.Router();
|
||||
/*
|
||||
|
||||
|
@ -8,11 +8,10 @@ const Tribes = require( '../models/Tribes.js' );
|
||||
// Middlewares
|
||||
const checkHeaders = require( '../middlewares/checkHeaders' );
|
||||
const isAuthenticated = require( '../middlewares/isAuthenticated' );
|
||||
const hasAccessrighton = require( '../middlewares/hasAccessrighton' );
|
||||
const router = express.Router();
|
||||
|
||||
|
||||
router.get('www', checkHeaders,isAuthenticated,hasAccessrighton('www','R'),(req,res)=>{
|
||||
router.get('www', checkHeaders,isAuthenticated,(req,res)=>{
|
||||
/**
|
||||
* @api {get} /tribes/www/:tribeId
|
||||
* @apiName Get list of www object (space web)
|
||||
@ -38,6 +37,19 @@ router.get('www', checkHeaders,isAuthenticated,hasAccessrighton('www','R'),(req,
|
||||
|
||||
//router.delete('www/:tribeId/:app)
|
||||
|
||||
router.post('/actionanonyme',checkHeaders,(req,res)=>{
|
||||
if (!fs.existsSync(`${conf.dirtown}/tribes/${req.session.header.xtribe}/actions/${req.body.action}.js`)){
|
||||
res.status(403).send({status:403,msg:"actionmissing",ref:"Tribes", data:{action:req.body.action,tribe:req.session.header.xtribe}})
|
||||
}
|
||||
const action = require(`${conf.dirtown}/tribes/${req.session.header.xtribe}/actions/${req.body.action}.js`)
|
||||
const resaction= action.run(req.body,req.session.header);
|
||||
res.status(resaction.status).send(resaction);
|
||||
})
|
||||
|
||||
router.post('/action',checkHeaders,isAuthenticated,(req,res)=>{
|
||||
|
||||
})
|
||||
|
||||
|
||||
router.get( '/clientconf/:tribeid', checkHeaders, isAuthenticated, ( req, res ) => {
|
||||
/*
|
||||
@ -151,9 +163,9 @@ router.put( '/sendjson', checkHeaders, isAuthenticated, ( req, res ) => {
|
||||
} else {
|
||||
if( fs.existsSync( `${config.tribes}/${req.session.header.xworkon}/${req.body.object}/${req.body.path}` ) ) {
|
||||
// exist so can be update check accessright update on this
|
||||
hasAccessrighton( req.body.object, "U" );
|
||||
//A REVOIR hasAccessrighton( req.body.object, "U" );
|
||||
} else {
|
||||
hasAccessrighton( req.body.object, "C" );
|
||||
// AREVOIRhasAccessrighton( req.body.object, "C" );
|
||||
}
|
||||
fs.outputJsonSync( dest, req.body.data );
|
||||
res.status( 200 )
|
||||
@ -224,7 +236,7 @@ router.delete( '/file', checkHeaders, isAuthenticated, ( req, res ) => {
|
||||
.send( { info: [ 'deleteerror' ], models: "Tribes", moreinfo: "your del req need a src" } )
|
||||
return;
|
||||
};
|
||||
hasAccessrighton( req.query.src.split( '/' )[ 0 ], "D" );
|
||||
// A REVOIR hasAccessrighton( req.query.src.split( '/' )[ 0 ], "D" );
|
||||
console.log( 'Remove file', `${config.tribes}/${req.session.header.xworkon}/${req.query.src}` )
|
||||
console.log( req.body )
|
||||
fs.removeSync( `${config.tribes}/${req.session.header.xworkon}/${req.query.src}` );
|
||||
|
@ -6,7 +6,7 @@ const Wwws = require("../models/Wwws.js");
|
||||
// Middlewares
|
||||
const checkHeaders = require("../middlewares/checkHeaders");
|
||||
const isAuthenticated = require("../middlewares/isAuthenticated");
|
||||
const hasAccessrighton = require("../middlewares/hasAccessrighton");
|
||||
|
||||
const router = express.Router();
|
||||
/**
|
||||
* To manage an nginx conf
|
||||
|
62
apxtrib.js
@ -29,7 +29,7 @@ To share configuration :
|
||||
*
|
||||
*
|
||||
* @param {args} args key:value example node apxtrib nationId:ants townId:devfarm dns:devfarm-ants
|
||||
* if no parammeter from adminapi/www/adminapx/conf/setup_xx.json
|
||||
* if no parameter from adminapi/www/adminapx/conf/setup_xx.json
|
||||
*
|
||||
* Keyword townId = "devfarm" then this is unchain town to dev
|
||||
* else this is a production town ready to chain to the nationId
|
||||
@ -66,7 +66,7 @@ if (fs.existsSync(`${__dirname}/adminapi/www/adminapx/conf/setup_xx.json`)) {
|
||||
infotown = fs.readJsonSync(
|
||||
`${__dirname}/adminapi/www/adminapx/conf/setup_xx.json`
|
||||
);
|
||||
};
|
||||
}
|
||||
if (
|
||||
Object.keys(param).length > 0 &&
|
||||
param.nationId &&
|
||||
@ -76,26 +76,28 @@ if (
|
||||
infotown.nationId = param.nationId;
|
||||
infotown.townId = param.townId;
|
||||
infotown.dns = param.dns;
|
||||
}
|
||||
}
|
||||
fs.outputJsonSync(
|
||||
`${__dirname}/adminapi/www/adminapx/conf/setup_xx.json`,
|
||||
infotown
|
||||
);
|
||||
infotown.dirapi=__dirname;
|
||||
infotown.dirtown=path.resolve(`${__dirname}/../${infotown.townId}-${infotown.nationId}`);
|
||||
process.env.dirtown=infotown.dirtown;
|
||||
|
||||
`${__dirname}/adminapi/www/adminapx/conf/setup_xx.json`,
|
||||
infotown
|
||||
);
|
||||
infotown.dirapi = __dirname;
|
||||
infotown.dirtown = path.resolve(
|
||||
`${__dirname}/../${infotown.townId}-${infotown.nationId}`
|
||||
);
|
||||
process.env.dirtown = infotown.dirtown;
|
||||
infotown.dirapxwebapp = path.resolve(`${infotown.dirapi}/..`); //same level as apxtrib
|
||||
if (
|
||||
!fs.existsSync(`${infotown.dirtown}/conf.json`) ||
|
||||
!fs.existsSync(`${__dirname}/adminapi/www/nginx_adminapx.conf`)
|
||||
) {
|
||||
// Case of new town or request a reset of dns to access adminapx
|
||||
// genere a minimum conf with nationId, townId, dns, dirapi, dirtown
|
||||
fs.outputJsonSync(`${infotown.dirtown}/conf.json`,infotown,{space:2});
|
||||
const Towns = require('./api/models/Towns')
|
||||
fs.outputJsonSync(`${infotown.dirtown}/conf.json`, infotown, { space: 2 });
|
||||
const Towns = require("./api/models/Towns");
|
||||
const rescreate = Towns.create();
|
||||
if (rescreate.status!=200){
|
||||
console.log('Sorry error ')
|
||||
if (rescreate.status != 200) {
|
||||
console.log("Sorry error ");
|
||||
process.exit();
|
||||
}
|
||||
}
|
||||
@ -120,6 +122,15 @@ let tribeIds = [];
|
||||
let routes = glob.sync(`${conf.dirapi}/api/routes/*.js`).map((f) => {
|
||||
return { url: `/${path.basename(f, ".js")}`, route: f };
|
||||
});
|
||||
|
||||
glob.sync(`${conf.dirtown}/tribes/*/api/routes/*.js`).forEach((f) => {
|
||||
const ids = f.indexOf(`${conf.dirtown}/tribes/`);
|
||||
const trib = f.slice(
|
||||
ids + `${conf.dirtown}/tribes/`.length,
|
||||
f.lastIndexOf("/api/routes")
|
||||
);
|
||||
routes.push({ url: `/${trib}/${path.basename(f, ".js")}`, route: f });
|
||||
});
|
||||
//routes={url,route} check how to add plugin tribe route later
|
||||
// keep only the 2 last part (.) of domain name to validate cors with it (generic domain)
|
||||
Object.keys(tribelist).forEach((t) => {
|
||||
@ -141,18 +152,20 @@ app.use(bodyParser.urlencoded(conf.api.bodyparse.urlencoded));
|
||||
// To set depending of post put json data size to send
|
||||
app.use(express.json());
|
||||
app.use(bodyParser.json(conf.api.bodyparse.json));
|
||||
app.disable('x-powered-by');// for security
|
||||
app.locals.tribeids = tribeIds;
|
||||
console.log("app.locals.tribeids", app.locals.tribeids);
|
||||
// Cors management
|
||||
const corsOptions = {
|
||||
origin: (origin, callback) => {
|
||||
if (origin === undefined) {
|
||||
callback(null, true);
|
||||
} else if (origin.indexOf("chrome-extension") > -1) {
|
||||
//before modif only origin == undefined
|
||||
if (
|
||||
(infotown.townId == "devfarm" &&
|
||||
(origin == undefined || origin == null)) ||
|
||||
origin.indexOf("chrome-extension") > -1
|
||||
) {
|
||||
callback(null, true);
|
||||
} else {
|
||||
//console.log( 'origin', origin )
|
||||
//marchais avant modif eslint const rematch = ( /^https?\:\/\/(.*)\:.*/g ).exec( origin )
|
||||
const rematch = /^https?:\/\/(.*):.*/g.exec(origin);
|
||||
//console.log( rematch )
|
||||
let tmp = origin.replace(/http.?:\/\//g, "").split(".");
|
||||
@ -169,8 +182,7 @@ const corsOptions = {
|
||||
if (doms.includes(dom)) {
|
||||
callback(null, true);
|
||||
} else {
|
||||
console.log(`Origin is not allowed by CORS`);
|
||||
callback(new Error("Not allowed by CORS"));
|
||||
callback(false);
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -184,11 +196,11 @@ app.use(cors(corsOptions));
|
||||
} ) );
|
||||
*/
|
||||
// Routers add any routes from /routes and /plugins
|
||||
let logroute = "Routes available on this apxtrib instance: ";
|
||||
let logroute = "Routes available on this apxtrib instance:\n ";
|
||||
|
||||
routes.forEach((r) => {
|
||||
try {
|
||||
logroute += r.url + "|" + r.route;
|
||||
logroute += r.url.padEnd(30,' ') + r.route +"\n ";
|
||||
app.use(r.url, require(r.route));
|
||||
} catch (err) {
|
||||
logroute += " (err check it)";
|
||||
@ -198,11 +210,11 @@ routes.forEach((r) => {
|
||||
console.log(logroute);
|
||||
if (infotown.townId == "devfarm") {
|
||||
console.log(
|
||||
`\x1b[42m############################################################################################\x1b[0m\n\x1b[42mThis is dev conf to switch this as production, you must run:\n 1 - 'yarn dev nationId:ants townId:usbfarm dns:usbfarm-ants ' to conf your town and check it.\n 2 - 'yarn startpm2'\n Where:\n\x1b[42m * nationId have to exist in the nationchains\n * townId new or if exist must have the smae current dns,\n * dns domaine that has to redirect 80/443 into this server (example wall-ants.ndda.fr redirect to 213.32.65.213 ).\n Check README's project to learn more.\x1b[0m\n\x1b[42m############################################################################################\x1b[0m`
|
||||
`\x1b[42m############################################################################################\x1b[0m\n\x1b[42mThis is dev conf accessible in http://devfarm-ants to switch this as production, you must run:\n 1 - 'yarn dev nationId:ants townId:usbfarm dns:usbfarm-ants ' to conf your town and check it.\n 2 - 'yarn startpm2'\n Where:\n\x1b[42m * nationId have to exist in the nationchains\n * townId new or if exist must have the smae current dns,\n * dns domaine that has to redirect 80/443 into this server (example wall-ants.ndda.fr redirect to 213.32.65.213 ).\n Check README's project to learn more.\x1b[0m\n To work with apxweb for the front use http://defarm-ants/apxweb/www/tplname/src/index.html to use the api during dev process\n\x1b[42m############################################################################################\x1b[0m`
|
||||
);
|
||||
}
|
||||
app.listen(conf.api.port, () => {
|
||||
let webaccess = `check in your browser that api works`;
|
||||
let webaccess = `api waits request on `;
|
||||
conf.dns.forEach((u) => {
|
||||
webaccess += `http://${u}:${conf.api.port}`;
|
||||
});
|
||||
|
10
package.json
@ -13,7 +13,7 @@
|
||||
"scripts": {
|
||||
"stoppm2": "pm2 stop apxtrib.js",
|
||||
"startpm2": "pm2 start apxtrib.js --log-date-format 'DD-MM HH:mm:ss.SSS'",
|
||||
"deletepm2":"pm2 delete apxtrib",
|
||||
"deletepm2": "pm2 delete apxtrib",
|
||||
"restartpm2": "pm2 restart apxtrib.js --log-date-format 'DD-MM HH:mm:ss.SSS'",
|
||||
"startblockchain": "pm2 start api/models/Blockchains.js --log-date-format 'DD-MM HH:mm:ss:SSS'",
|
||||
"logpm2": "pm2 logs apxtrib.js --lines 200",
|
||||
@ -75,13 +75,13 @@
|
||||
"luxon": "^2.1.1",
|
||||
"moment": "^2.22.1",
|
||||
"mustache": "^2.3.0",
|
||||
"node-mailjet": "^6.0.2",
|
||||
"nodemailer": "^6.1.1",
|
||||
"nodemailer-smtp-transport": "^2.7.4",
|
||||
"openpgp": "^5.8.0",
|
||||
"nodemailer": "^6.9.7",
|
||||
"openpgp": "^5.10.1",
|
||||
"path": "^0.12.7",
|
||||
"pdf-creator-node": "^2.2.2",
|
||||
"pm2": "^5.1.2",
|
||||
"readline-sync": "^1.4.10",
|
||||
"smtp-client": "^0.4.0",
|
||||
"stripe": "^7.4.0",
|
||||
"uuid": "^9.0.0"
|
||||
},
|
||||
|
33
unittest.js
@ -1,9 +1,11 @@
|
||||
const fs = require("fs-extra");
|
||||
const glob = require("glob");
|
||||
const path = require("path");
|
||||
const process = require("process");
|
||||
//const config = require( './tribes/townconf.js' );
|
||||
const config = {
|
||||
/*const config = {
|
||||
unittesting: ["middlewares", "models", "routes", "nationchains"],
|
||||
};
|
||||
};*/
|
||||
|
||||
global.__base = __dirname + "/";
|
||||
const ut = {};
|
||||
@ -40,7 +42,7 @@ module.exports=ut;
|
||||
To request any update or change in the code add to your git branch a new file into where you test your modifications /inittest/
|
||||
We first run your test and check with git diff your code before merge your branch with your inittest
|
||||
|
||||
You'll be inform when a new release including your change into azpXtrib will be available.
|
||||
You'll be inform when a new release including your change into apXtrib will be available.
|
||||
\x1b[7mThanks for improving our democracy tool.\x1b[0m
|
||||
`;
|
||||
ut.run = (options) => {
|
||||
@ -66,6 +68,15 @@ ut.run = (options) => {
|
||||
}
|
||||
});
|
||||
};
|
||||
//get town conf
|
||||
const infotown = fs.readJsonSync(
|
||||
`${__dirname}/adminapi/www/adminapx/conf/setup_xx.json`
|
||||
);
|
||||
infotown.dirtown = path.resolve(
|
||||
`${__dirname}/../${infotown.townId}-${infotown.nationId}`
|
||||
);
|
||||
const conf = fs.readJSONSync(`${infotown.dirtown}/conf.json`);
|
||||
process.env.dirtown = infotown.dirtown;
|
||||
const options = { filetotest: [] };
|
||||
process.argv.slice(2).forEach((arg) => {
|
||||
switch (arg.substring(0, 2)) {
|
||||
@ -81,9 +92,9 @@ process.argv.slice(2).forEach((arg) => {
|
||||
break;
|
||||
default:
|
||||
options.active = true;
|
||||
config.unittesting.forEach((codefolder) => {
|
||||
conf.api.unittesting.forEach((codefolder) => {
|
||||
glob
|
||||
.sync(`${__dirapi}${codefolder}/**/unittest/${arg}.js`)
|
||||
.sync(`${__dirname}/api/${codefolder}/**/unittest/${arg}.js`)
|
||||
.forEach((f) => {
|
||||
if (!options.filetotest.includes(f)) options.filetotest.push(f);
|
||||
});
|
||||
@ -92,14 +103,16 @@ process.argv.slice(2).forEach((arg) => {
|
||||
}
|
||||
});
|
||||
if (!options.active) {
|
||||
config.unittesting.forEach((codefolder) => {
|
||||
glob.sync(`${__dirapi}${codefolder}/**/unittest/*.js`).forEach((f) => {
|
||||
if (!options.filetotest.includes(f)) options.filetotest.push(f);
|
||||
});
|
||||
conf.api.unittesting.forEach((codefolder) => {
|
||||
glob
|
||||
.sync(`${conf.dirapi}/api/${codefolder}/**/unittest/*.js`)
|
||||
.forEach((f) => {
|
||||
if (!options.filetotest.includes(f)) options.filetotest.push(f);
|
||||
});
|
||||
});
|
||||
console.log(
|
||||
"You can test only some unittest by passing yarn unittest name where name is a /unittest/name.js file that exist, type 'yarn unittest -help' for more"
|
||||
);
|
||||
console.log("Looking for unittest folder into ", config.unittesting);
|
||||
console.log("Looking for unittest folder into ", conf.api.unittesting);
|
||||
}
|
||||
options.help ? console.log(ut.help) : ut.run(options);
|
||||
|