ajout des fichiers du projet TheNewJoplin

This commit is contained in:
bruno 2022-11-10 15:55:58 -05:00
parent 88f05c5529
commit 45a6522e2f
9 changed files with 924 additions and 31 deletions

View File

@ -18,11 +18,8 @@
*** for contributors-url, forks-url, etc. This is an optional, concise syntax you may use.
*** https://www.markdownguide.org/basic-syntax/#reference-style-links
-->
[![Contributors][contributors-shield]][contributors-url]
[![Forks][forks-shield]][forks-url]
[![Stargazers][stars-shield]][stars-url]
[![Issues][issues-shield]][issues-url]
[![MIT License][license-shield]][license-url]
[![GNU License][license-shield]][license-url]
[![Nim][Nim.com]][Nim-url]
[![LinkedIn][linkedin-shield]][linkedin-url]
@ -70,6 +67,11 @@
</ul>
</li>
<li><a href="#usage">Usage</a></li>
<li><a href="#base">Base</a></li>
<li><a href="#usage">Usage</a></li>
<li><a href="#usage">Usage</a></li>
<li><a href="#usage">Usage</a></li>
<li><a href="#usage">Usage</a></li>
<li><a href="#roadmap">Roadmap</a></li>
<li><a href="#contributing">Contributing</a></li>
<li><a href="#license">License</a></li>
@ -78,41 +80,63 @@
</ol>
</details>
<!-- ABOUT THE PROJECT -->
## About The Project
[![Product Name Screen Shot][product-screenshot]](https://example.com)
[![Product Name Screen Shot][product-screenshot]](https://git.bcmaison.cf/Projets/nim-lib/src/branch/main/images/screenshot.png)
There are many great README templates available on GitHub; however, I didn't find one that really suited my needs so I created this enhanced one. I want to create a README template so amazing that it'll be the last one you ever need -- I think this is it.
Cette librairie permet de centraliser tous les types de besoins génériques à une même place. Elle est découpé en plusieurs regroupement :
Here's why:
* Your time should be focused on creating something amazing. A project that solves a problem and helps others
* You shouldn't be doing the same tasks over and over like creating a README from scratch
* You should implement DRY principles to the rest of your life :smile:
Of course, no one template will serve all projects since your needs may be different. So I'll be adding more in the near future. You may also suggest changes by forking this repo and creating a pull request or opening an issue. Thanks to all the people have contributed to expanding this template!
| Section | script | description |
| -------------------- | ----------------------- | ---------------------------------------------------------------------------- |
| 📂 base | 📄 OutilsBase.nim | Fonctions de base, petit traitement et opérations sur chaines, encryption. |
| 📂 commun | 📄 OutilsCommun.nim | Traitement et fonctions communes sur heures, date, os, fichiers, répertoires |
| 📂 commun | 📄 password_utils.nim | |
| 📂 commun | 📄 utils.nim | |
| 📂 commun ➡️ load | 📄 | Fonctions de chargement des données de divers types (CSV, list, json, ...) |
| 📂 commun ➡️ save | 📄 | Fonctions de sauvegarde des données de divers types (CSV, list, json, ...) |
| 📂 Communication | 📄 | Fonctions de communications |
| 📂 Comm. ➡️ discord | 📄 | communication de type discord |
| 📂 Comm. ➡️ email | 📄 | communication de type email |
| 📂 Comm. ➡️ server | 📄 | communication de type serveur |
| 📂 Comm. ➡️ Joplin | 📄 joplin_json_utils.nim | communication de type Joplin |
| 📂 Comm. ➡️ Joplin | 📄 joplin_utils.nim | communication de type Joplin |
| 📂 db | 📄 database_utils.nim | Fonctions de type base de données |
| 📂 listes | 📄 | Fonctions de traitement de listes |
| 📂 windows ➡️ registry | 📄 | (Windows) Fonctions de traitement sur clé de registre |
| 📂 windows ➡️ wmi | 📄 | (Windows) Fonctions de traitement sur WMI |
| 📂 web | 📄 web_utils.nim | Fonctions de type web |
Use the `BLANK_README.md` to get started.
<p align="right">(<a href="#readme-top">back to top</a>)</p>
### Built With
This section should list any major frameworks/libraries used to bootstrap your project. Leave any add-ons/plugins for the acknowledgements section. Here are a few examples.
Ces fonctions sont fait pour des projets développés en Nim. Voici la liste des modules a importer par script.
* [![Next][Next.js]][Next-url]
* [![React][React.js]][React-url]
* [![Vue][Vue.js]][Vue-url]
* [![Angular][Angular.io]][Angular-url]
* [![Svelte][Svelte.dev]][Svelte-url]
* [![Laravel][Laravel.com]][Laravel-url]
* [![Bootstrap][Bootstrap.com]][Bootstrap-url]
* [![JQuery][JQuery.com]][JQuery-url]
* [![Nim][Nim.com]][Nim-url]
| Section | script | modules |
| -------------------- | ----------------------- | -------------------------------- |
| 📂 base | 📄 OutilsBase.nim | |
| 📂 commun | 📄 OutilsCommun.nim | |
| 📂 commun | 📄 password_utils.nim | md5, bcrypt, random |
| 📂 commun | 📄 utils.nim | std/times |
| 📂 commun ➡️ load | | |
| 📂 commun ➡️ save | | |
| 📂 Communication | | |
| 📂 Comm. ➡️ discord | | |
| 📂 Comm. ➡️ email | | |
| 📂 Comm. ➡️ server | | |
| 📂 Comm. ➡️ Joplin | 📄 joplin_json_utils.nim | |
| 📂 Comm. ➡️ Joplin | 📄 joplin_utils.nim | |
| 📂 db | 📄 database_utils.nim | os, logging, parsecfg, db_sqlite |
| 📂 listes | 📄 listes_utils.nim | |
| 📂 windows ➡️ registry | 📄 registry_utils.nim | |
| 📂 windows ➡️ wmi | 📄 wmi_utils.nim | |
| 📂 web | 📄 web_utils.nim | |
[![Nim][Nim.com]][Nim-url]
<p align="right">(<a href="#readme-top">back to top</a>)</p>
@ -163,6 +187,12 @@ _For more examples, please refer to the [Documentation](https://example.com)_
<p align="right">(<a href="#readme-top">back to top</a>)</p>
<!-- SECTION BASE -->
## Base
Détails, spécifications spécial sur la section Base
<p align="right">(<a href="#readme-top">back to top</a>)</p>
<!-- ROADMAP -->
@ -245,13 +275,13 @@ Use this space to list resources you find helpful and would like to give credit
[forks-shield]: https://img.shields.io/github/forks/othneildrew/Best-README-Template.svg?style=for-the-badge
[forks-url]: https://github.com/othneildrew/Best-README-Template/network/members
[stars-shield]: https://img.shields.io/github/stars/othneildrew/Best-README-Template.svg?style=for-the-badge
[stars-url]: https://github.com/othneildrew/Best-README-Template/stargazers
[stars-url]: https://git.bcmaison.cf/Projets/nim-lib/stars
[issues-shield]: https://img.shields.io/github/issues/othneildrew/Best-README-Template.svg?style=for-the-badge
[issues-url]: https://github.com/othneildrew/Best-README-Template/issues
[license-shield]: https://img.shields.io/github/license/othneildrew/Best-README-Template.svg?style=for-the-badge
[license-url]: https://github.com/othneildrew/Best-README-Template/blob/master/LICENSE.txt
[license-shield]: https://img.shields.io/badge/LICENSE-GNU-green?style=for-the-badge
[license-url]: https://git.bcmaison.cf/Projets/nim-lib/src/branch/main/LICENSE.txt
[linkedin-shield]: https://img.shields.io/badge/-LinkedIn-black.svg?style=for-the-badge&logo=linkedin&colorB=555
[linkedin-url]: https://linkedin.com/in/othneildrew
[linkedin-url]: https://www.linkedin.com/in/bruno-charest-a3a6158/
[product-screenshot]: images/screenshot.png
[Next.js]: https://img.shields.io/badge/next.js-000000?style=for-the-badge&logo=nextdotjs&logoColor=white
[Next-url]: https://nextjs.org/

View File

View File

View File

@ -0,0 +1,56 @@
# --==--==--==--==--==--==--==--==--==--==--==--==--==--==--==-- #
# Bruno Charest
# 2022-08-09
#
# __ DESCRIPTIONS __
# password_utils : procedure related password
#
# Inspiration of : https://ttj.dk/blog/2019/01/20/setup-a-website-with-nim
# Copyright 2019 - Thomas T. Jarløv
# --==--==--==--==--==--==--==--==--==--==--==--==--==--==--==-- #
import md5
import bcrypt
import random
randomize()
# --==--==--==--==--==--==--==--==--==--==-- #
# Let and VAR : for random
# --==--==--==--==--==--==--==--==--==--==-- #
var urandom: File
let useUrandom = urandom.open("/dev/urandom")
# --==--==--==--==--==--==--==--==--==--==--=--==--==--=--==--==--=--==--==-- #
# PROC : Make Salt
## : Generate random salt. Uses cryptographically secure /dev/urandom
## : on platforms where it is available, and Nim's random module in other cases.
# --==--==--==--==--==--==--==--==--==--==--=--==--==--=--==--==--=--==--==-- #
proc makeSalt*(): string =
result = ""
if useUrandom:
var randomBytes: array[0..127, char]
discard urandom.readBuffer(addr(randomBytes), 128)
for ch in randomBytes:
if ord(ch) in {32..126}:
result.add(ch)
else:
for i in 0..127:
result.add(chr(rand(94) + 32)) # Generate numbers from 32 to 94 + 32 = 126
# --==--==--==--==--==--==--==--==--==--==-- #
# PROC : Make session key
## Creates a random key to be used to authorize a session.
# --==--==--==--==--==--==--==--==--==--==-- #
proc makeSessionKey*(): string =
let random = makeSalt()
return bcrypt.hash(random, genSalt(8))
# --==--==--==--==--==--==--==--==--==--==-- #
# PROC : make password
## Creates an MD5 hash by combining password and salt
# --==--==--==--==--==--==--==--==--==--==-- #
proc makePassword*(password, salt: string, comparingTo = ""): string =
let bcryptSalt = if comparingTo != "": comparingTo else: genSalt(8)
result = hash(getMD5(salt & getMD5(password)), bcryptSalt)

22
outils/commun/utils.nim Normal file
View File

@ -0,0 +1,22 @@
# --==--==--==--==--==--==--==--==--==--==--==--==--==--==--==-- #
# Bruno Charest
# 2022-10-25
#
# __ DESCRIPTIONS __
# utils : procedures generals utils
#
# --==--==--==--==--==--==--==--==--==--==--==--==--==--==--==-- #
import std/times
# --==--==--==--==--==--==--==--==--==--==--==--==--==--==-- #
# PROC : Convert epoch millisecond time to human readable time
# --==--==--==--==--==--==--==--==--==--==--==--==--==--==-- #
proc convertEpochToHumanTime*(epochTime: int): string =
var humanTime: Time
var dateTime: string
humanTime = fromUnix(convert(Milliseconds, Seconds, epochTime))
dateTime = format(humanTime, "yyyy-MM-dd' 'HH:mm")
# echo dateTime
return dateTime

View File

@ -0,0 +1,24 @@
# --==--==--==--==--==--==--==--==--==--==--==--==--==--==--==-- #
# Bruno Charest
# 2022-08-09
#
# __ DESCRIPTIONS __
# joplin_json_utils : Types and procedure related to json request
#
# [TODO] joplin_json_utils : need to create many procedures
# --==--==--==--==--==--==--==--==--==--==--==--==--==--==--==-- #
# --==--==--==--==--==--==--==--==--==--==-- #
# TYPE : Data structure for TAGS
# --==--==--==--==--==--==--==--==--==--==-- #
type Tag = object
id : string
parent_id : string
title: string
type Tags = object
items: seq[Tag]
has_more: string

View File

@ -0,0 +1,516 @@
# --==--==--==--==--==--==--==--==--==--==--==--==--==--==--==-- #
# Bruno Charest
# 2022-08-09
#
# __ DESCRIPTIONS __
# joplin_utils : procedure related joplin application
#
# --==--==--==--==--==--==--==--==--==--==--==--==--==--==--==-- #
import os
import net
import times
import osproc
import jester
import std/json
import httpcore
import strutils
import strformat
import std/options
import std/httpclient
import std/asyncdispatch
import ../../commun/utils # Joplin utils procedures and types
# from os import sleep
from posix import read, write, fdatasync, close
# --==--==--==--==--==--==--==--==--==--==-- #
# TYPE : Setup joplin_ping data
# --==--==--==--==--==--==--==--==--==--==-- #
type
joplin_ping* = object
ping_result*: seq[string]
ping_status*: bool
req*: Request
# --==--==--==--==--==--==--==--==--==--==-- #
# TYPE : Setup joplin_tags data
# --==--==--==--==--==--==--==--==--==--==-- #
type
joplin_tags* = object
id*, parent_id*, title*: seq[string]
created_time*, updated_time*, user_created_time*, user_updated_time*,
is_shared*: seq[int]
req*: Request
# --==--==--==--==--==--==--==--==--==--==-- #
# TYPE : Setup joplin_notebooks data
# --==--==--==--==--==--==--==--==--==--==-- #
type
joplin_notebooks* = object
id*, parent_id*, title*, share_id*, icon*: seq[string]
created_time*, updated_time*, user_created_time*, user_updated_time*,
is_shared*: seq[int]
req*: Request
# --==--==--==--==--==--==--==--==--==--==-- #
# TYPE : Setup joplin_notes data
# --==--==--==--==--==--==--==--==--==--==-- #
type
joplin_notes* = object
id*, parent_id*, title*, body*, author*, source_url*, source*,
source_application*, application_data*, share_id*,
conflict_original_id*, body_html*, base_url*: seq[string]
updated_time*, is_conflict*, is_todo*, todo_due*,
todo_completed*, user_created_time*, user_updated_time*,
markup_language*, is_shared*: seq[int]
latitude*, longitude*, altitude*, order*: seq[float]
created_time*: seq[string]
req*: Request
# --==--==--==--==--==--==--==--==--==--==-- #
# TYPE : Setup joplin_note data
# --==--==--==--==--==--==--==--==--==--==-- #
type
joplin_note* = object
id*, parent_id*, title*, body*, author*, source_url*, source*,
source_application*, application_data*, conflict_original_id*,
master_key_id*, share_id*, encryption_cipher_text * : string
created_time*, updated_time*, user_created_time*, user_updated_time*,
is_conflict*, is_todo*, todo_due*, todo_completed*, markup_language*,
is_shared*, encryption_applied*: int
latitude*, longitude*, altitude*, order*: float
req*: Request
# --==--==--==--==--==--==--==--==--==--==-- #
# TYPE : Setup process data structure
# --==--==--==--==--==--==--==--==--==--==-- #
type
program* = object
pid*: int
stdout*: string
stderr*: string
# --==--==--==--==--==--==--==--==--==--==-- #
# DURATION : duration variables
# --==--==--==--==--==--==--==--==--==--==-- #
let
resetDuration = initDuration(seconds = 2)
deciSecondDuration* = initDuration(milliseconds = 100)
qtrsecondDuration* = initDuration(milliseconds = 250)
# --==--==--==--==--==--==--==--==--==--==-- #
# VAR : connexion http variables
# --==--==--==--==--==--==--==--==--==--==-- #
var
client = newHttpClient()
lastConnection = getTime().utc
# --==--==--==--==--==--==--==--==--==--==-- #
# PROC : reset HTTP client
# --==--==--==--==--==--==--==--==--==--==-- #
proc resetHttpClient() =
if (getTime().utc - lastConnection) > resetDuration:
# Probably a new timeout. We have not yet experienced a long outage.
# We may however be entering an extended outage.
# Creating the new clients seems to use up lots of CPU.
# I want to do that as little as possible.
try:
client.close()
except:
echo("Attempted to close clients. Probably do not exist.")
echo("Current exception: ", getCurrentExceptionMsg())
client = newHttpClient(timeout = 500)
# --==--==--==--==--==--==--==--==--==--==--==--==--==-==--==--==- #
# PROC : use the joplin API ping to validate service availibility
# --==--==--==--==--==--==--==--==--==--==--==--==--==-==--==--==- #
proc ping_joplin*(token: string): Future[joplin_ping] {.async.} =
var j_p: joplin_ping
var client = newAsyncHttpClient()
var url: string
j_p.ping_status = false
try:
url = fmt"http://localhost:41184/ping?token={token}"
var json = await client.getContent(url)
j_p.ping_result.add(json)
echo j_p.ping_result[0]
if j_p.ping_result[0] == "JoplinClipperServer":
j_p.ping_status = true
except TimeoutError, IOError, OSError:
# I naively think I would see this thrown or the plain except below.
# But I almost never see an Error raised.
echo("Current Exception: ", getCurrentException().name)
echo("Current Exception Msg: ", getCurrentExceptionMsg())
echo("Sleeping for 1 seconds at: ", getTime().utc)
sleep(500)
resetHttpClient()
j_p.ping_status = false
except:
echo("Current Exception: ", getCurrentException().name)
echo("Current Exception Msg: ", getCurrentExceptionMsg())
echo("Sleeping for 1 seconds at: ", getTime().utc)
j_p.ping_status = false
return j_p
# parse jason
#let joplin_notes_Json = parseJson(json)
# --==--==--==--==--==--==--==--==--==--==-- #
# PROC : get all joplin NOTEBOOKS
# --==--==--==--==--==--==--==--==--==--==-- #
proc get_joplin_notebooks*(token: string): Future[joplin_notebooks] {.async.} =
# Variables
var j_nb: joplin_notebooks
var has_more: bool = true
var page: int = 1
var url: string
var client = newAsyncHttpClient()
var pingCheck: joplin_ping
pingCheck = waitFor ping_joplin(token)
# check the joplin status befor query
if pingCheck.ping_status:
# make sure to check all pages
while has_more == true:
# request joplin API for notebooks
url = fmt"http://localhost:41184/folders?page={page}&token={token}"
echo("URL notebooks : ", url)
var json = await client.getContent(url)
# parse jason
let joplin_notebooks_Json = parseJson(json)
# valider qu'il n'y a plus de page
if not joplin_notebooks_Json["has_more"].getBool:
has_more = false
# store json info into an object
var count: int = 1
for nb in joplin_notebooks_Json["items"]:
j_nb.id.add(nb["id"].getstr)
j_nb.parent_id.add(nb["parent_id"].getstr)
j_nb.title.add(nb["title"].getstr)
count += 1
# aller à la page suivante
page += 1
return j_nb
# --==--==--==--==--==--==--==--==--==--==-- #
# PROC : get all joplin NOTES
# --==--==--==--==--==--==--==--==--==--==-- #
proc get_joplin_notes*(token: string): Future[joplin_notes] {.async.} =
# Variables
var j_notes: joplin_notes
var has_more: bool = true
var page: int = 1
var url: string
var client = newAsyncHttpClient()
var pingCheck: joplin_ping
pingCheck = waitFor ping_joplin(token)
# check the joplin status befor query
if pingCheck.ping_status:
# make sure to check all pages
while has_more == true:
# request joplin API for Notes
url = fmt"http://localhost:41184/notes?page={page}&fields=id,parent_id,title,created_time,updated_time&token={token}"
echo("URL notes : ", url)
var json = await client.getContent(url)
# parse jason
let joplin_notes_Json = parseJson(json)
# valider qu'il n'y a plus de page
if not joplin_notes_Json["has_more"].getBool:
has_more = false
#echo joplin_notes_Json
# store json info into an object
var count: int = 1
var epochTime: int
var humanTime: Time
for nb in joplin_notes_Json["items"]:
j_notes.id.add(nb["id"].getstr)
j_notes.parent_id.add(nb["parent_id"].getstr)
j_notes.title.add(nb["title"].getstr)
#epochTime = nb["created_time"].getInt
#humanTime = fromUnix(convert(Milliseconds, Seconds, epochTime))
j_notes.created_time.add(convertEpochToHumanTime(nb[
"created_time"].getInt))
count += 1
# aller à la page suivante
page += 1
return j_notes
# --==--==--==--==--==--==--==--==--==--==-- #
# PROC : get joplin NOTE
# --==--==--==--==--==--==--==--==--==--==-- #
proc get_joplin_note*(token: string, noteid: string): Future[
joplin_note] {.async.} =
# Variables
var j_note: joplin_note
var has_more: bool = true
var page: int = 1
var url: string
var client = newAsyncHttpClient()
# Check joplin connection availibility
var pingCheck: joplin_ping
pingCheck = waitFor ping_joplin(token)
# Query for a selected note
url = fmt"http://localhost:41184/notes/{noteid}?fields=id,parent_id,title,body,created_time,updated_time,is_conflict,latitude,longitude,altitude,author,source_url,is_todo,todo_due,todo_completed,source,source_application,application_data,order,user_created_time,user_updated_time,encryption_cipher_text,encryption_applied,markup_language,is_shared,share_id,conflict_original_id,master_key_id&token={token}"
echo("URL notes : ", url)
var jsonNote = await client.getContent(url)
# parse jason
let joplin_note_Json = parseJson(jsonNote)
# get all informations for a selected note
j_note.id = joplin_note_Json["id"].getstr
j_note.parent_id = joplin_note_Json["parent_id"].getstr
j_note.title = joplin_note_Json["title"].getstr
j_note.body = joplin_note_Json["body"].getstr
j_note.author = joplin_note_Json["author"].getstr
j_note.source_url = joplin_note_Json["source_url"].getstr
j_note.source = joplin_note_Json["source"].getstr
j_note.source_application = joplin_note_Json["source_application"].getstr
j_note.application_data = joplin_note_Json["application_data"].getstr
j_note.share_id = joplin_note_Json["share_id"].getstr
j_note.conflict_original_id = joplin_note_Json["conflict_original_id"].getstr
j_note.created_time = joplin_note_Json["created_time"].getInt
j_note.updated_time = joplin_note_Json["updated_time"].getInt
j_note.is_conflict = joplin_note_Json["is_conflict"].getInt
j_note.latitude = joplin_note_Json["latitude"].getFloat
j_note.longitude = joplin_note_Json["longitude"].getFloat
j_note.altitude = joplin_note_Json["altitude"].getFloat
j_note.is_todo = joplin_note_Json["is_todo"].getInt
j_note.todo_due = joplin_note_Json["todo_due"].getInt
j_note.todo_completed = joplin_note_Json["todo_completed"].getInt
j_note.order = joplin_note_Json["order"].getFloat
j_note.user_created_time = joplin_note_Json["user_created_time"].getInt
j_note.user_updated_time = joplin_note_Json["user_updated_time"].getInt
j_note.encryption_cipher_text = joplin_note_Json[
"encryption_cipher_text"].getstr
j_note.encryption_applied = joplin_note_Json["encryption_applied"].getInt
j_note.markup_language = joplin_note_Json["markup_language"].getInt
j_note.is_shared = joplin_note_Json["is_shared"].getInt
j_note.master_key_id = joplin_note_Json["master_key_id"].getstr
echo j_note
return j_note
# --==--==--==--==--==--==--==--==--==--==-- #
# PROC : get all joplin TAGS
# --==--==--==--==--==--==--==--==--==--==-- #
proc get_joplin_tags*(token: string): Future[joplin_tags] {.async.} =
# Variables
var j_tags: joplin_tags
var has_more: bool = true
var page: int = 1
var url: string
var client = newAsyncHttpClient()
var pingCheck: joplin_ping
pingCheck = waitFor ping_joplin(token)
# check the joplin status befor query
if pingCheck.ping_status:
# make sure to check all pages
while has_more == true:
# request joplin API for notebooks
url = fmt"http://localhost:41184/tags?page={page}&token={token}"
echo("URL tags : ", url)
var json = await client.getContent(url)
# parse jason
let joplin_tags_Json = parseJson(json)
# valider qu'il n'y a plus de page
if not joplin_tags_Json["has_more"].getBool:
has_more = false
# store json info into an object
var count: int = 1
for nb in joplin_tags_Json["items"]:
j_tags.id.add(nb["id"].getstr)
j_tags.parent_id.add(nb["parent_id"].getstr)
j_tags.title.add(nb["title"].getstr)
count += 1
# aller à la page suivante
page += 1
return j_tags
# --==--==--==--==--==--==--==--==--==--==-- #
# PROC : get the token from Joplin Terminal
# --==--==--==--==--==--==--==--==--==--==-- #
proc get_joplin_cli_token*(): string =
var flagName: string = ""
var flagValue: string = ""
var result = execCmdEx("joplin config api.token")
if result.exitCode == 0:
let param1 = result.output
let flagSplit = param1.split(" = ")
flagName = flagSplit[0]
flagValue = flagSplit[1]
return flagValue
# --==--==--==--==--==--==--==--==--==--==-- #
# PROC : launch any program and get PID
# --==--==--==--==--==--==--==--==--==--==-- #
proc launchProgram(app: string = "", workingPath: string = "", arguments: array[
2, string]): int {.thread.} =
var p = startProcess(joinPath(workingPath, app), workingPath, arguments)
let pid = p.processID()
var outhdl = outputHandle(p)
var inputhdl = inputHandle(p)
var errhdl = errorHandle(p)
return pid
# --==--==--==--==--==--==--==--==--==--==-- #
# PROC : Start joplin cli
# --==--==--==--==--==--==--==--==--==--==-- #
proc joplin_cli_start*(): int {.thread.} =
let joplinProcessId = launchProgram("joplin", "/usr/bin/", ["server", "start"])
return joplinProcessId
# --==--==--==--==--==--==--==--==--==--==-- #
# PROC : stop Joplin Terminal
# --==--==--==--==--==--==--==--==--==--==-- #
proc joplin_cli_stop*(): int {.thread.} =
let joplinProcessId = launchProgram("joplin", "/usr/bin/", ["server", "stop"])
return joplinProcessId
# --==--==--==--==--==--==--==--==--==--==-- #
# PROC : check Joplin Terminal staus
# --==--==--==--==--==--==--==--==--==--==-- #
proc joplin_cli_status*(): bool =
var rc = false
var result = execCmdEx("joplin server status")
if result.exitCode == 0:
if "Server is not running" in result.output:
echo "Joplin Terminal cli status is down : ", result.output
rc = false
else:
echo "Joplin Terminal cli status is up : ", result.output
rc = true
else:
echo "Error validate joplin terminal status : ", result.output
return rc
# --==--==--==--==--==--==--==--==--==--==-- #
# PROC : start or stop Joplin Terminal
# --==--==--==--==--==--==--==--==--==--==-- #
proc joplin_cli_start_stop*(): int =
var isStart: int = 0
var sleep_delay_frame: int = 50
var sleep_max: int = 5000
if joplin_cli_status() == false:
isStart = joplin_cli_start()
while joplin_cli_status() == false:
sleep(sleep_delay_frame)
echo "Joplin client Terminal started: ", isStart
else:
echo "Joplin client Terminal is alredy started !"
#if joplin_cli_status() == true:
isStart = joplin_cli_stop()
while joplin_cli_status() == true:
sleep(sleep_delay_frame)
echo "Joplin client Terminal stopped: ", isStart
return isStart
# --==--==--==--==--==--==--==--==--==--==-- #
# PROC :
# --==--==--==--==--==--==--==--==--==--==-- #
# proc get_joplin_tags_json*(token:string): Future[] {.async.} =
# # url = fmt"http://localhost:41184/notes/{id}?fields=id,parent_id,title,body,created_time,updated_time,is_conflict,latitude,longitude,altitude,author,source_url,is_todo,todo_due,todo_completed,source,source_application,application_data,order,user_created_time,user_updated_time,encryption_cipher_text,encryption_applied,markup_language,is_shared,share_id,conflict_original_id,master_key_id&token={token}"
# # url = fmt"http://localhost:41184/tags/{id}?fields=id,parent_id,title,created_time,updated_time,user_created_time,user_updated_time,is_shared&token={token}"
# # http://localhost:41184/tags?token=e5f6644fbf6a97ddc55648dae72b11caecda6c6642d8ce0d3b20129b89b196385737eb908923542c3343649ebbf865b55bda031ab4c3a16edc7723ef2ad77d8f
# # Variables
# var j_tags: joplin_tags
# var has_more: bool = true
# var page: int = 1
# var url: string
# var client = newAsyncHttpClient()
# var pingCheck: joplin_ping
# pingCheck = waitFor ping_joplin(token)
# # check the joplin status befor query
# if pingCheck.ping_status:
# # make sure to check all pages
# while has_more == true:
# # request joplin API for notebooks
# url = fmt"http://localhost:41184/tags?page={page}&token={token}"
# echo("URL tags : ", url)
# var json = await client.getContent(url)
# # parse jason
# let joplin_tags_Json = parseJson(json)
# # valider qu'il n'y a plus de page
# if not joplin_tags_Json["has_more"].getBool:
# has_more = false
# # store json info into an object
# var count: int = 1
# for nb in joplin_tags_Json["items"]:
# echo nb["id"].getstr
# echo nb["parent_id"].getstr
# echo nb["title"].getstr
# count += 1
# # aller à la page suivante
# page += 1

View File

@ -0,0 +1,132 @@
# --==--==--==--==--==--==--==--==--==--==--==--==--==--==--==-- #
# Bruno Charest
# 2022-08-09
#
# __ DESCRIPTIONS __
# database_utils : procedure related to database
#
# Inspiration of : https://ttj.dk/blog/2019/01/20/setup-a-website-with-nim
# Copyright 2019 - Thomas T. Jarløv
# --==--==--==--==--==--==--==--==--==--==--==--==--==--==--==-- #
import os
import logging
import parsecfg
import db_sqlite
import ../commun/password_utils
# --==--==--==--==--==--==--==--==--==--==-- #
# PROC : Generate Database
# --==--==--==--==--==--==--==--==--==--==-- #
proc generateDB*() =
echo "Generating database"
# Load the connection details
let
dict = loadConfig("config/config.cfg")
db_user = dict.getSectionValue("Database", "user")
db_pass = dict.getSectionValue("Database", "pass")
db_name = dict.getSectionValue("Database", "name")
db_host = dict.getSectionValue("Database", "host")
db_folder = dict.getSectionValue("Database", "folder")
dbexists = if fileExists(db_host): true else: false
if dbexists:
echo " - Database already exists. Inserting tables if they do not exist."
# Creating database folder if it doesn't exist
discard existsOrCreateDir(db_folder)
# Open DB
echo " - Opening database"
var db = open(connection = db_host, user = db_user, password = db_pass,
database = db_name)
# Person table contains information about the
# registrered users
if not db.tryExec(sql("""
create table if not exists person(
id integer primary key,
name varchar(60) not null,
password varchar(300) not null,
email varchar(254) not null,
creation timestamp not null default (STRFTIME('%s', 'now')),
modified timestamp not null default (STRFTIME('%s', 'now')),
salt varbin(128) not null,
status varchar(30) not null,
timezone VARCHAR(100),
secretUrl VARCHAR(250),
lastOnline timestamp not null default (STRFTIME('%s', 'now'))
);""")):
echo " - Database: person table already exists"
# Session table contains information about the users
# cookie ID, IP and last visit
if not db.tryExec(sql("""
create table if not exists session(
id integer primary key,
ip inet not null,
key varchar(300) not null,
userid integer not null,
lastModified timestamp not null default (STRFTIME('%s', 'now')),
foreign key (userid) references person(id)
);""")):
echo " - Database: session table already exists"
# Sesion table contains information about the search
#
if not db.tryExec(sql("""
create table if not exists search(
id integer primary key,
search_title varchar(300) not null,
query varchar(300) not null,
search_type varchar(100) not null,
creation timestamp not null default (STRFTIME('%s', 'now')),
lastModified timestamp not null default (STRFTIME('%s', 'now')),
foreign key (userid) references person(id)
);""")):
echo " - Database: search table already exists"
# --==--==--==--==--==--==--==--==--==--==-- #
# PROC : Create Administrator User
# --==--==--==--==--==--==--==--==--==--==-- #
proc createAdminUser*(db: DbConn, args: seq[string]) =
## Create new admin user
var iName = ""
var iEmail = ""
var iPwd = ""
# Loop through all the arguments and get the args
# containing the user information
for arg in args:
if arg.substr(0, 1) == "u:":
iName = arg.substr(2, arg.len())
elif arg.substr(0, 1) == "p:":
iPwd = arg.substr(2, arg.len())
elif arg.substr(0, 1) == "e:":
iEmail = arg.substr(2, arg.len())
# If the name, password or emails does not exists
# return error
if iName == "" or iPwd == "" or iEmail == "":
error("Missing either name, password or email to create the Admin user.")
# Generate the password using a salt and hashing.
# Read more about hashing and salting here:
# - https://crackstation.net/hashing-security.htm
# - https://en.wikipedia.org/wiki/Salt_(cryptography)
let salt = makeSalt()
let password = makePassword(iPwd, salt)
# Insert user into database
if insertID(db, sql"INSERT INTO person (name, email, password, salt, status) VALUES (?, ?, ?, ?, ?)",
$iName, $iEmail, password, salt, "Admin") > 0:
echo "Admin user added"
else:
error("Something went wrong")
info("Admin added.")

113
outils/web/web_utils.nim Normal file
View File

@ -0,0 +1,113 @@
# --==--==--==--==--==--==--==--==--==--==--==--==--==--==--==-- #
# Bruno Charest
# 2022-08-09
#
# __ DESCRIPTIONS __
# web_utils : procedure related web interface
#
# --==--==--==--==--==--==--==--==--==--==--==--==--==--==--==-- #
import xlsx # read dashbord.xlsx
import jester
import ../communication/joplin/joplin_utils
import strutils
import std/asyncdispatch
# --==--==--==--==--==--==--==--==--==--==-- #
# TYPE : Selected Option for master web page
# --==--==--==--==--==--==--==--==--==--==-- #
type
selectedOption* = enum
newNote = "New Note", search = "Search", shortcuts = "Shortcuts",
notes = "Notes", notebooks = "Notesbooks", tags = "Tags",
notes_selectednote = "Notes-SelectedNote", dashbord = "Dashboard"
# --==--==--==--==--==--==--==--==--==--==-- #
# TYPE : Dashbord information
# --==--==--==--==--==--==--==--==--==--==-- #
type DashbordData* = object
position*: seq[int]
ext_link*: seq[string]
int_link*: seq[string]
ip_link*: seq[string]
title*: seq[string]
description*: seq[string]
server*: seq[string]
ip*: seq[string]
port*: seq[int]
ssl*: seq[bool]
category*: seq[string]
icon*: seq[string]
open_method*: seq[string]
tag*: seq[seq[string]]
hotkey*: seq[string]
color*: seq[string]
# --==--==--==--==--==--==--==--==--==--==-- #
# TYPE : Data Informations for Left Colomn
# --==--==--==--==--==--==--==--==--==--==-- #
type ColomnLeftData* = ref object of RootObj
j_status*: bool
option*: selectedOption
j_notes*: joplin_notes
j_notes_nb*: int
j_notebooks*: joplin_notebooks
j_notebooks_nb*: int
j_tags*: joplin_tags
j_tags_nb*: int
dashbord*: DashbordData
req*: Request
# --==--==--==--==--==--==--==--==--==--==-- #
# TYPE : Data Informations for Right Colomn
# --==--==--==--==--==--==--==--==--==--==-- #
type ColomnRightData* = ref object of RootObj
j_status*: bool
option*: selectedOption
j_SelectedNote*: joplin_note
j_notebooksNote*: joplin_notebooks
j_tagsNote*: joplin_tags
req*: Request
# --==--==--==--==--==--==--==--==--==--==--==--==--==--==-- #
# PROC : get data from dashbord file
# --==--==--==--==--==--==--==--==--==--==--==--==--==--==-- #
proc getDashbordData*(): Future[DashbordData] {.async.} =
var ddata: DashbordData
var tagslist: seq[string]
let
data = parseExcel("data/dashbord.xlsx", header = true)
sheetName = "dashbord"
#echo data[sheetName]
let rows = data[sheetName].toSeq(true)
echo rows.len()
for i in 0..(rows.len()-1):
ddata.position.add(parseInt(rows[i][0]))
ddata.ext_link.add(rows[i][1])
ddata.int_link.add(rows[i][2])
ddata.ip_link.add(rows[i][3])
ddata.title.add(rows[i][4])
ddata.description.add(rows[i][5])
ddata.server.add(rows[i][6])
ddata.ip.add(rows[i][7])
ddata.port.add(parseInt(rows[i][8]))
if rows[i][9] == "OUI":
ddata.ssl.add(true)
else:
ddata.ssl.add(false)
ddata.category.add(rows[i][10])
ddata.icon.add(rows[i][11])
ddata.open_method.add(rows[i][12])
tagslist = rows[i][13].split(',')
ddata.tag.add(tagslist)
ddata.hotkey.add(rows[i][14])
ddata.color.add(rows[i][15])
echo ddata
return ddata