Compare commits

...

30 Commits

Author SHA1 Message Date
poka 4dc34fb64e update requirements 2023-09-15 10:16:33 +02:00
poka cb7037072e add dict annotation 2023-09-13 09:06:44 +02:00
poka 1737080b82 fix command with no args 2023-09-10 11:33:31 +02:00
poka 56f5972ad0 refacto args passing 2023-09-10 09:44:52 +02:00
poka 5fe53c1d4c refacto arguments parsing 2023-09-10 08:15:56 +02:00
poka 919a4171f5 bump 0.1.0 2023-09-10 02:23:44 +02:00
poka 6dc86592b9 refacto and translate main file 2023-09-10 02:03:42 +02:00
poka 595f7722bf refacto #1 2023-09-10 01:53:38 +02:00
poka e188d4da94 unindent json 2023-09-09 22:35:35 +02:00
poka aa6fd2b738 antispam: improve condition 2023-09-09 13:26:27 +02:00
poka 676fbbfa9b antispam: remove unknown wallet by GVA 2023-09-09 12:51:47 +02:00
poka 3492643d4f add map option to walletList 2023-09-09 10:14:31 +02:00
poka b1049bd7b7 Merge branch 'refactoGeolocProfiles' 2023-09-09 09:50:52 +02:00
poka 2c5435a18b add sublevel in json, with timestamp 2023-09-09 09:50:20 +02:00
poka 51ae54484c remove unused imports 2023-09-09 09:44:27 +02:00
poka e0ba392671 add geolocProfiles command 2023-09-09 09:38:22 +02:00
poka ab50340595 update vscode settings 2023-09-09 04:26:50 +02:00
poka b89456a9b4 Merge branch 'g1walletbot' 2023-09-09 00:16:01 +02:00
Kapis a13723fa3c showing hash in json output 2023-03-16 18:45:34 +01:00
poka bdc8b938fc Merge pull request 'Adding blockstamp to history JSON' (#24) from g1walletbot into master
Reviewed-on: axiom-team/jaklis#24
2023-03-14 21:20:18 +01:00
Kapis fc587819b0 Adding blockstamp to history JSON 2023-03-14 20:35:17 +01:00
poka b6dbc5f8da Merge pull request 'JSON history added field status and new GVA node' (#23) from kapis/jaklis:master into master
Reviewed-on: axiom-team/jaklis#23
2023-03-11 21:18:20 +01:00
Kapis dbbd2c3ed6 more info about dunikey path 2023-03-11 21:12:57 +01:00
Kapis 31f4fc1f83 added Poka node 2023-03-10 22:21:33 +01:00
Kapis 4a1cae165a Added pini GVA node 2023-03-10 22:21:33 +01:00
Kapis 249aa2c6a7 adding status to json history output 2023-03-10 22:21:33 +01:00
Kapis afd244d405 ignoring pycache 2023-03-10 22:21:33 +01:00
poka b047142b64 change default duniter node 2023-03-10 22:20:58 +01:00
poka 0c264fc57c hello aya 2023-01-21 11:31:19 +01:00
poka afad8092b7 fix setup symlink 2023-01-21 11:29:29 +01:00
15 changed files with 735 additions and 333 deletions

View File

@ -1,9 +1,11 @@
# Chemin de la clé privé Ḡ1 de l'émetteur, au format PubSec # Chemin de la clé privé Ḡ1 de l'émetteur, au format PubSec
DUNIKEY= # ex. DUNIKEY="/path/myprivateG1key.dunikey"
DUNIKEY=""
# Noeud Duniter # Noeud Duniter
DUNITER="https://g1.librelois.fr" DUNITER="https://g1.asycn.io"
#DUNITER="http://g1.duniter.org" #DUNITER="https://duniter.pini.fr"
#DUNITER="https://g1v1.p2p.legal"
# Adresse du pod Cesium ou Gchange à utiliser # Adresse du pod Cesium ou Gchange à utiliser
ESNODE="https://g1.data.e-is.pro" ESNODE="https://g1.data.e-is.pro"

3
.gitignore vendored
View File

@ -1,6 +1,5 @@
.env .env
__pycache__
*.dunikey *.dunikey
not4U not4U
.vscode/settings.json .vscode/settings.json
__pycache__

6
.vscode/settings.json vendored Normal file → Executable file
View File

@ -1,3 +1,7 @@
{ {
"python.pythonPath": "/usr/bin/python3.9" "python.pythonPath": "/usr/bin/python3.9",
"[python]": {
"editor.defaultFormatter": "ms-python.black-formatter"
},
"python.formatting.provider": "none"
} }

567
jaklis.py
View File

@ -1,210 +1,395 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import argparse, sys, os, getpass, string, random import argparse
from os.path import join, dirname import sys
from shutil import copyfile import os
import string
import random
from dotenv import load_dotenv from dotenv import load_dotenv
from duniterpy.key import SigningKey from duniterpy.key import SigningKey
from pathlib import Path
from lib.gva import GvaApi
from lib.cesium import CesiumPlus
__version__ = "0.0.5" __version__ = "0.1.1"
MY_PATH = os.path.realpath(sys.argv[0]).replace('jaklis.py','') MY_PATH = Path(__file__).resolve().parent
# Get variables environment # Set file paths
if not os.path.isfile(MY_PATH + '.env'): dotenv_file = MY_PATH / ".env"
copyfile(MY_PATH + ".env.template",MY_PATH + ".env") dotenv_template = MY_PATH / ".env.template"
dotenv_path = join(dirname(__file__),MY_PATH + '.env')
load_dotenv(dotenv_path)
# Set global values (default parameters) , regarding variables environments # Check and create dotenv file
node = os.getenv('DUNITER') + '/gva' if not dotenv_file.is_file():
if not node: dotenv_file.write_text(dotenv_template.read_text())
node="https://g1.librelois.fr/gva"
pod = os.getenv('ESNODE') # Load environment variables
if not pod: load_dotenv(dotenv_file)
pod="https://g1.data.e-is.pro"
# Set global values (default parameters) regarding environment variables
node = os.getenv("DUNITER") + "/gva" or "https://g1v1.p2p.legal/gva"
pod = os.getenv("ESNODE") or "https://g1.data.e-is.pro"
destPubkey = False destPubkey = False
# Parse arguments # define parser
parser = argparse.ArgumentParser(description="Client CLI pour Cesium+ et Ḡchange", epilog="current node: '" + node + "', current pod: '" + pod + "'.") parser = argparse.ArgumentParser(
parser.add_argument('-v', '--version', action='store_true', help="Affiche la version actuelle du programme") description="CLI Client for Cesium+ and Ḡchange",
parser.add_argument('-k', '--key', help="Chemin vers mon trousseau de clé (PubSec)") epilog="current node: '" + node + "', current pod: '" + pod + "'.",
parser.add_argument('-n', '--node', help="Adresse du noeud Cesium+, Gchange ou Duniter à utiliser") )
subparsers = parser.add_subparsers(title="Commandes de jaklis", dest="cmd") # load global arguments
read_cmd = subparsers.add_parser('read', help="Lecture des messages") parser.add_argument(
send_cmd = subparsers.add_parser('send', help="Envoi d'un message") "-v",
delete_cmd = subparsers.add_parser('delete', help="Supression d'un message") "--version",
getProfile_cmd = subparsers.add_parser('get', help="Voir un profile Cesium+") action="store_true",
getPage_cmd = subparsers.add_parser('page', help="Voir une page Cesium+") help="Display the current program version",
setProfile_cmd = subparsers.add_parser('set', help="Configurer son profile Cesium+") )
eraseProfile_cmd = subparsers.add_parser('erase', help="Effacer son profile Cesium+") parser.add_argument("-k", "--key", help="Path to the keyfile (PubSec)")
stars_cmd = subparsers.add_parser('stars', help="Voir les étoiles d'un profile / Noter un profile (option -s NOTE)") parser.add_argument(
unstars_cmd = subparsers.add_parser('unstars', help="Supprimer un star") "-n", "--node", help="Address of the Cesium+, Gchange, or Duniter node to use"
getoffer_cmd = subparsers.add_parser('getoffer', help="Obtenir les informations d'une annonce gchange") )
setoffer_cmd = subparsers.add_parser('setoffer', help="Créer une annonce gchange")
deleteoffer_cmd = subparsers.add_parser('deleteoffer', help="Supprimer une annonce gchange")
pay_cmd = subparsers.add_parser('pay', help="Payer en Ḡ1")
history_cmd = subparsers.add_parser('history', help="Voir l'historique des transactions d'un compte Ḡ1")
balance_cmd = subparsers.add_parser('balance', help="Voir le solde d'un compte Ḡ1")
id_cmd = subparsers.add_parser('id', help="Voir l'identité d'une clé publique/username")
id_balance_cmd = subparsers.add_parser('idBalance', help="Voir l'identité d'une clé publique/username et son solde")
currentUd = subparsers.add_parser('currentUd', help="Affiche la montant actuel du dividende Universel")
listWallets = subparsers.add_parser('listWallets', help="Liste de toutes les portefeuilles G1")
# Messages management # Define commands with arguments
read_cmd.add_argument('-n', '--number',type=int, default=3, help="Affiche les NUMBER derniers messages") commands = {
read_cmd.add_argument('-j', '--json', action='store_true', help="Sort au format JSON") "read": {
read_cmd.add_argument('-o', '--outbox', action='store_true', help="Lit les messages envoyés") "help": "Read messages",
"arguments": {
("n", "number"): {
"type": int,
"default": 3,
"help": "Display the last NUMBER messages",
},
("j", "json"): {"action": "store_true", "help": "Output in JSON format"},
("o", "outbox"): {"action": "store_true", "help": "Read sent messages"},
},
"type": "cesium",
},
"send": {
"help": "Send a message",
"arguments": {
("d", "destinataire"): {
"required": True,
"help": "Recipient of the message",
},
("t", "titre"): {"help": "Title of the message to send"},
("m", "message"): {"help": "Message to send"},
("f", "fichier"): {"help": "Send the message from the 'FILE'"},
("o", "outbox"): {
"action": "store_true",
"help": "Send the message to the outbox",
},
},
"type": "cesium",
},
"delete": {
"help": "Delete a message",
"arguments": {
("i", "id"): {
"action": "append",
"nargs": "+",
"required": True,
"help": "ID(s) of the message(s) to delete",
},
("o", "outbox"): {
"action": "store_true",
"help": "Delete a sent message",
},
},
"type": "cesium",
},
"get": {
"help": "View a Cesium+ profile",
"arguments": {
("p", "profile"): {"help": "Profile name"},
("a", "avatar"): {
"action": "store_true",
"help": "Also retrieve the avatar in raw base64 format",
},
},
"type": "cesium",
},
"page": {
"help": "View a Cesium+ page",
"arguments": {
("p", "page"): {"help": "Page name"},
("a", "avatar"): {
"action": "store_true",
"help": "Also retrieve the page's avatar in raw base64 format",
},
},
"type": "cesium",
},
"set": {
"help": "Configure your Cesium+ profile",
"arguments": {
("n", "name"): {"help": "Profile name"},
("d", "description"): {"help": "Profile description"},
("v", "ville"): {"help": "Profile city"},
("a", "adresse"): {"help": "Profile address"},
("pos", "position"): {
"nargs": 2,
"help": "Geographical coordinates (lat + lon)",
},
("s", "site"): {"help": "Profile website"},
("A", "avatar"): {"help": "Path to profile avatar in PNG"},
},
"type": "cesium",
},
"erase": {
"help": "Erase your Cesium+ profile",
"arguments": {},
"type": "cesium",
},
"stars": {
"help": "View a profile's stars / Rate a profile (option -s RATING)",
"arguments": {
("p", "profile"): {"help": "Target profile"},
("n", "number"): {"type": int, "help": "Number of stars"},
},
"type": "cesium",
},
"unstars": {
"help": "Remove a star",
"arguments": {
("p", "profile"): {"help": "Profile to unstar"},
},
"type": "cesium",
},
"getoffer": {
"help": "Get information about a Ḡchange listing",
"arguments": {
("i", "id"): {"help": "Target listing to retrieve"},
},
"type": "cesium",
},
"setoffer": {
"help": "Create a Ḡchange listing",
"arguments": {
("t", "title"): {"help": "Title of the listing to create"},
("d", "description"): {"help": "Description of the listing to create"},
("c", "category"): {"help": "Category of the listing to create"},
("l", "location"): {
"nargs": 2,
"help": "Location of the listing to create (lat + lon)",
},
("p", "picture"): {"help": "Image of the listing to create"},
("ci", "city"): {"help": "City of the listing to create"},
("pr", "price"): {"help": "Price of the listing to create"},
},
"type": "cesium",
},
"deleteoffer": {
"help": "Delete a Ḡchange listing",
"arguments": {
("i", "id"): {"help": "Target listing to delete"},
},
"type": "cesium",
},
"geolocProfiles": {
"help": "Get JSON of all geolocated accounts",
"arguments": {},
"type": "cesium",
},
"pay": {
"help": "Pay in Ḡ1",
"arguments": {
("p", "pubkey"): {"help": "Payment recipient"},
("a", "amount"): {"type": float, "help": "Transaction amount"},
("c", "comment"): {
"default": "",
"help": "Transaction comment",
"nargs": "*",
},
("m", "mempool"): {
"action": "store_true",
"help": "Use mempool sources",
},
("v", "verbose"): {
"action": "store_true",
"help": "Display the JSON result of the transaction",
},
},
"type": "gva",
},
"history": {
"help": "View Ḡ1 account transaction history",
"arguments": {
("p", "pubkey"): {"help": "Public key of the target account"},
("n", "number"): {
"type": int,
"default": 10,
"help": "Display the last NUMBER transactions",
},
("j", "json"): {
"action": "store_true",
"help": "Display the result in JSON format",
},
("nocolors"): {
"action": "store_true",
"help": "Display the result in black and white",
},
},
"type": "gva",
},
"balance": {
"help": "View Ḡ1 account balance",
"arguments": {
("p", "pubkey"): {"help": "Public key of the target account"},
("m", "mempool"): {
"action": "store_true",
"help": "Use mempool sources",
},
},
"type": "gva",
},
"id": {
"help": "View public key/username identity",
"arguments": {
("p", "pubkey"): {"help": "Public key of the target account"},
("u", "username"): {"help": "Username of the target account"},
},
"type": "gva",
},
"idBalance": {
"help": "View public key/username identity and balance",
"arguments": {
("p", "pubkey"): {"help": "Public key of the target account"},
},
"type": "gva",
},
"currentUd": {
"help": "Display the current Universal Dividend amount",
"arguments": {
("p", "pubkey"): {"help": "Public key of the target account"},
},
"type": "gva",
},
"listWallets": {
"help": "List all G1 wallets",
"arguments": {
("m", "mbr"): {
"action": "store_true",
"help": "Display raw list of member pubkeys",
},
("nm", "non_mbr"): {
"action": "store_true",
"help": "Display raw list of nonmember identity pubkeys",
},
("l", "larf"): {
"action": "store_true",
"help": "Display raw list of nonmember pubkeys",
},
("b", "brut"): {
"action": "store_true",
"help": "Display raw list of all pubkeys",
},
},
"type": "gva",
},
}
send_cmd.add_argument('-d', '--destinataire', required=True, help="Destinataire du message") # Process commands and arguments
send_cmd.add_argument('-t', '--titre', help="Titre du message à envoyer") subparsers = parser.add_subparsers(title="jaklis Commands", dest="cmd")
send_cmd.add_argument('-m', '--message', help="Message à envoyer") for cmd, cmd_info in commands.items():
send_cmd.add_argument('-f', '--fichier', help="Envoyer le message contenu dans le fichier 'FICHIER'") cmd_parser = subparsers.add_parser(cmd, help=cmd_info["help"])
send_cmd.add_argument('-o', '--outbox', action='store_true', help="Envoi le message sur la boite d'envoi") for args, kwargs in cmd_info["arguments"].items():
if isinstance(args, str):
delete_cmd.add_argument('-i', '--id', action='append', nargs='+', required=True, help="ID(s) du/des message(s) à supprimer") cmd_parser.add_argument("--" + args, **kwargs)
delete_cmd.add_argument('-o', '--outbox', action='store_true', help="Suppression d'un message envoyé") else:
short_arg, long_arg = args
# Profiles management cmd_parser.add_argument("-" + short_arg, "--" + long_arg, **kwargs)
setProfile_cmd.add_argument('-n', '--name', help="Nom du profile")
setProfile_cmd.add_argument('-d', '--description', help="Description du profile")
setProfile_cmd.add_argument('-v', '--ville', help="Ville du profile")
setProfile_cmd.add_argument('-a', '--adresse', help="Adresse du profile")
setProfile_cmd.add_argument('-pos', '--position', nargs=2, help="Points géographiques (lat + lon)")
setProfile_cmd.add_argument('-s', '--site', help="Site web du profile")
setProfile_cmd.add_argument('-A', '--avatar', help="Chemin vers mon avatar en PNG")
getProfile_cmd.add_argument('-p', '--profile', help="Nom du profile")
getProfile_cmd.add_argument('-a', '--avatar', action='store_true', help="Récupérer également l'avatar au format raw base64")
getPage_cmd.add_argument('-p', '--page', help="Nom de la page")
getPage_cmd.add_argument('-a', '--avatar', action='store_true', help="Récupérer également l'avatar au format raw base64")
# Likes management
stars_cmd.add_argument('-p', '--profile', help="Profile cible")
stars_cmd.add_argument('-n', '--number', type=int, help="Nombre d'étoile")
unstars_cmd.add_argument('-p', '--profile', help="Profile à dénoter")
# Offers management
getoffer_cmd.add_argument('-i', '--id', help="Annonce cible à récupérer")
setoffer_cmd.add_argument('-t', '--title', help="Titre de l'annonce à créer")
setoffer_cmd.add_argument('-d', '--description', help="Description de l'annonce à créer")
setoffer_cmd.add_argument('-c', '--category', help="Categorie de l'annonce à créer")
setoffer_cmd.add_argument('-l', '--localisation', nargs=2, help="Localisation de l'annonce à créer (lat + lon)")
setoffer_cmd.add_argument('-p', '--picture', help="Image de l'annonce à créer")
setoffer_cmd.add_argument('-ci', '--city', help="Ville de l'annonce à créer")
setoffer_cmd.add_argument('-pr', '--price', help="Prix de l'annonce à créer")
deleteoffer_cmd.add_argument('-i', '--id', help="Annonce cible à supprimer")
# GVA usage
pay_cmd.add_argument('-p', '--pubkey', help="Destinataire du paiement")
pay_cmd.add_argument('-a', '--amount', type=float, help="Montant de la transaction")
pay_cmd.add_argument('-c', '--comment', default="", help="Commentaire de la transaction", nargs='*')
pay_cmd.add_argument('-m', '--mempool', action='store_true', help="Utilise les sources en Mempool")
pay_cmd.add_argument('-v', '--verbose', action='store_true', help="Affiche le résultat JSON de la transaction")
history_cmd.add_argument('-p', '--pubkey', help="Clé publique du compte visé")
history_cmd.add_argument('-n', '--number',type=int, default=10, help="Affiche les NUMBER dernières transactions")
history_cmd.add_argument('-j', '--json', action='store_true', help="Affiche le résultat en format JSON")
history_cmd.add_argument('--nocolors', action='store_true', help="Affiche le résultat en noir et blanc")
balance_cmd.add_argument('-p', '--pubkey', help="Clé publique du compte visé")
balance_cmd.add_argument('-m', '--mempool', action='store_true', help="Utilise les sources en Mempool")
id_cmd.add_argument('-p', '--pubkey', help="Clé publique du compte visé")
id_cmd.add_argument('-u', '--username', help="Username du compte visé")
id_balance_cmd.add_argument('-p', '--pubkey', help="Pubkey du compte visé")
currentUd.add_argument('-p', '--pubkey', help="Pubkey du compte visé")
listWallets.add_argument('-b', '--balance', action='store_true', help="Affiche les soldes")
listWallets.add_argument('--mbr', action='store_true', help="Affiche la liste de pubkey membres brut")
listWallets.add_argument('--non_mbr', action='store_true', help="Affiche la liste de pubkey des identités non membres brut")
listWallets.add_argument('--larf', action='store_true', help="Affiche la liste des pubkey non membres brut")
listWallets.add_argument('--brut', action='store_true', help="Affiche la liste de toutes les pubkey brut")
listWallets.add_argument('-p', '--pubkey', help="useless but needed")
args = parser.parse_args() args = parser.parse_args()
args_dict = vars(args)
cmd = args.cmd cmd = args.cmd
if args.version: if args.version:
print(__version__) print(__version__)
sys.exit(0) sys.exit(0)
if not cmd: if not cmd:
parser.print_help() parser.print_help()
sys.exit(1) sys.exit(0)
def createTmpDunikey(): def createTmpDunikey():
# Generate pseudo-random nonce # Generate a pseudo-random nonce
nonce=[] nonce = "".join(
for _ in range(32): random.choice(string.ascii_letters + string.digits) for _ in range(32)
nonce.append(random.choice(string.ascii_letters + string.digits)) )
nonce = ''.join(nonce)
keyPath = "/tmp/secret.dunikey-" + nonce keyPath = "/tmp/secret.dunikey-" + nonce
# key = SigningKey.from_credentials(getpass.getpass("Identifiant: "), getpass.getpass("Mot de passe: "), None) # Create a dummy key (replace with actual key creation logic)
key = SigningKey.from_credentials("sgse547yhd54xv6541srdh", "sfdgwdrhpkxdawsbszqpof1sdg65xc", None) key = SigningKey.from_credentials(
"sgse547yhd54xv6541srdh", "sfdgwdrhpkxdawsbszqpof1sdg65xc", None
)
key.save_pubsec_file(keyPath) key.save_pubsec_file(keyPath)
return keyPath return keyPath
# Check if we need dunikey
try:
pubkey = args.pubkey
except:
pubkey = False
try:
profile = args.profile
except:
profile = False
# print(pubkey, profile) def get_arg_value(args, arg):
if cmd in ('history','balance','get','page','id','idBalance','listWallets') and (pubkey or profile):
noNeedDunikey = True
keyPath = False
try: try:
dunikey = args.pubkey return getattr(args, arg)
except: except AttributeError:
dunikey = args.profile return False
else:
noNeedDunikey = False
def get_dunikey(args):
if args.key: if args.key:
dunikey = args.key return args.key
keyPath = False dunikey = os.getenv("DUNIKEY")
else: if not dunikey:
dunikey = os.getenv('DUNIKEY') keyPath = createTmpDunikey()
if not dunikey: dunikey = keyPath
keyPath = createTmpDunikey()
dunikey = keyPath
else:
keyPath = False
if not os.path.isfile(dunikey): if not os.path.isfile(dunikey):
HOME = os.getenv("HOME") HOME = os.getenv("HOME")
dunikey = HOME + dunikey dunikey = HOME + dunikey
if not os.path.isfile(dunikey): if not os.path.isfile(dunikey):
sys.stderr.write('Le fichier de trousseau {0} est introuvable.\n'.format(dunikey)) sys.stderr.write("The keyfile {0} is not found.\n".format(dunikey))
sys.exit(1) sys.exit(1)
return dunikey
# Construct CesiumPlus object pubkey = get_arg_value(args, "pubkey")
if cmd in ("read","send","delete","set","get","page","erase","stars","unstars","getoffer","setoffer","deleteoffer"): profile = get_arg_value(args, "profile")
from lib.cesium import CesiumPlus
if args.node: noNeedDunikey = cmd in (
pod = args.node "history",
"balance",
"page",
"id",
"idBalance",
"listWallets",
"geolocProfiles",
) and (pubkey or profile)
cesium = CesiumPlus(dunikey, pod, noNeedDunikey) if noNeedDunikey:
dunikey = pubkey if pubkey else profile
else:
dunikey = get_dunikey(args)
keyPath = False if dunikey else createTmpDunikey()
def handle_cesium_commands(args, cmd, cesium):
# Get args of the command
cmd_args = (
list(zip(*list(commands[cmd]["arguments"].keys())))[1]
if len(commands[cmd]["arguments"].keys()) > 0
else []
)
cmd_args_dict = {arg: args_dict[arg] for arg in cmd_args if arg in args_dict}
cmd_args_values = list(cmd_args_dict.values())
# Messaging # Messaging
if cmd == "read": if cmd == "read":
cesium.read(args.number, args.outbox, args.json) cesium.read(*cmd_args_values)
elif cmd == "send": elif cmd == "send":
if args.fichier: if args.fichier:
with open(args.fichier, 'r') as f: with open(args.fichier, "r") as f:
msgT = f.read() msgT = f.read()
titre = msgT.splitlines(True)[0].replace('\n', '') titre = msgT.splitlines(True)[0].replace("\n", "")
msg = ''.join(msgT.splitlines(True)[1:]) msg = "".join(msgT.splitlines(True)[1:])
if args.titre: if args.titre:
titre = args.titre titre = args.titre
msg = msgT msg = msgT
@ -212,8 +397,8 @@ if cmd in ("read","send","delete","set","get","page","erase","stars","unstars","
titre = args.titre titre = args.titre
msg = args.message msg = args.message
else: else:
titre = input("Indiquez le titre du message: ") titre = input("Enter the message title: ")
msg = input("Indiquez le contenu du message: ") msg = input("Enter the message content: ")
cesium.send(titre, msg, args.destinataire, args.outbox) cesium.send(titre, msg, args.destinataire, args.outbox)
@ -222,13 +407,15 @@ if cmd in ("read","send","delete","set","get","page","erase","stars","unstars","
# Profiles # Profiles
elif cmd == "set": elif cmd == "set":
cesium.set(args.name, args.description, args.ville, args.adresse, args.position, args.site, args.avatar) cesium.set(**cmd_args_dict)
elif cmd == "get": elif cmd == "get":
cesium.get(args.profile, args.avatar) cesium.get(**cmd_args_dict)
elif cmd == "page": elif cmd == "page":
cesium.getPage(args.page, args.avatar) cesium.getPage(**cmd_args_dict)
elif cmd == "erase": elif cmd == "erase":
cesium.erase() cesium.erase()
elif cmd == "geolocProfiles":
cesium.geolocProfiles(node)
# Stars # Stars
elif cmd == "stars": elif cmd == "stars":
@ -243,21 +430,22 @@ if cmd in ("read","send","delete","set","get","page","erase","stars","unstars","
elif cmd == "getoffer": elif cmd == "getoffer":
cesium.getOffer(args.id) cesium.getOffer(args.id)
elif cmd == "setoffer": elif cmd == "setoffer":
cesium.setOffer(args.title, args.description, args.city, args.localisation, args.category, args.price, args.picture) cesium.setOffer(**cmd_args_dict)
elif cmd == "deleteoffer": elif cmd == "deleteoffer":
cesium.deleteOffer(args.id) cesium.deleteOffer(**cmd_args_dict)
else:
raise ValueError(f"Unknown command: {cmd}")
# Construct GVA object
elif cmd in ("pay","history","balance","id","idBalance","currentUd","listWallets"):
from lib.gva import GvaApi
if args.node: def handle_gva_commands(args, cmd, gva):
node = args.node # Get args of the command
cmd_args = (
if args.pubkey: list(zip(*list(commands[cmd]["arguments"].keys())))[1]
destPubkey = args.pubkey if len(commands[cmd]["arguments"].keys()) > 0
else []
gva = GvaApi(dunikey, node, destPubkey, noNeedDunikey) )
cmd_args_dict = {arg: args_dict[arg] for arg in cmd_args if arg in args_dict}
# cmd_args_values = list(cmd_args_dict.values())
if cmd == "pay": if cmd == "pay":
gva.pay(args.amount, args.comment, args.mempool, args.verbose) gva.pay(args.amount, args.comment, args.mempool, args.verbose)
@ -266,14 +454,37 @@ elif cmd in ("pay","history","balance","id","idBalance","currentUd","listWallets
elif cmd == "balance": elif cmd == "balance":
gva.balance(args.mempool) gva.balance(args.mempool)
elif cmd == "id": elif cmd == "id":
gva.id(args.pubkey, args.username) gva.id(**cmd_args_dict)
elif cmd == "idBalance": elif cmd == "idBalance":
gva.idBalance(args.pubkey) gva.idBalance(**cmd_args_dict)
elif cmd == "currentUd": elif cmd == "currentUd":
gva.currentUd() gva.currentUd()
elif cmd == "listWallets": elif cmd == "listWallets":
gva.listWallets(args.brut, args.mbr, args.non_mbr, args.larf) gva.listWallets(args.brut, args.mbr, args.non_mbr, args.larf)
else:
raise ValueError(f"Unknown command: {cmd}")
# Construct the CesiumPlus object
if commands[cmd]["type"] == "cesium":
if args.node:
pod = args.node
cesium = CesiumPlus(dunikey, pod, noNeedDunikey)
handle_cesium_commands(args, cmd, cesium)
# Construct the GvaApi object
elif commands[cmd]["type"] == "gva":
if args.node:
node = args.node
if hasattr(args, "pubkey"):
destPubkey = args.pubkey
gva = GvaApi(dunikey, node, destPubkey, noNeedDunikey)
handle_gva_commands(args, cmd, gva)
else:
raise ValueError(f"Unknown command: {cmd}")
if keyPath: if keyPath:
os.remove(keyPath) os.remove(keyPath)

View File

@ -1,17 +1,19 @@
import json
import re, string, random, base64 import re, string, random, base64
from lib.cesiumCommon import CesiumCommon, PUBKEY_REGEX from lib.cesiumCommon import CesiumCommon, PUBKEY_REGEX
from lib.geolocProfiles import GeolocProfiles
from lib.getPages import Pages from lib.getPages import Pages
from lib.messaging import ReadFromCesium, SendToCesium, DeleteFromCesium from lib.messaging import ReadFromCesium, SendToCesium, DeleteFromCesium
from lib.profiles import Profiles from lib.profiles import Profiles
from lib.stars import ReadLikes, SendLikes, UnLikes from lib.stars import ReadLikes, SendLikes, UnLikes
from lib.offers import Offers from lib.offers import Offers
class CesiumPlus(CesiumCommon):
class CesiumPlus(CesiumCommon):
#################### Messaging #################### #################### Messaging ####################
def read(self, nbrMsg, outbox, isJSON): def read(self, nbrMsg, isJSON, outbox):
readCesium = ReadFromCesium(self.dunikey, self.pod) readCesium = ReadFromCesium(self.dunikey, self.pod)
jsonMsg = readCesium.sendDocument(nbrMsg, outbox) jsonMsg = readCesium.sendDocument(nbrMsg, outbox)
if isJSON: if isJSON:
jsonFormat = readCesium.jsonMessages(jsonMsg, nbrMsg, outbox) jsonFormat = readCesium.jsonMessages(jsonMsg, nbrMsg, outbox)
@ -24,16 +26,18 @@ class CesiumPlus(CesiumCommon):
sendCesium.recipient = recipient sendCesium.recipient = recipient
# Generate pseudo-random nonce # Generate pseudo-random nonce
nonce=[] nonce = []
for _ in range(32): for _ in range(32):
nonce.append(random.choice(string.ascii_letters + string.digits)) nonce.append(random.choice(string.ascii_letters + string.digits))
sendCesium.nonce = base64.b64decode(''.join(nonce)) sendCesium.nonce = base64.b64decode("".join(nonce))
finalDoc = sendCesium.configDoc(sendCesium.encryptMsg(title), sendCesium.encryptMsg(msg)) # Configure JSON document to send finalDoc = sendCesium.configDoc(
sendCesium.sendDocument(finalDoc, outbox) # Send final signed document sendCesium.encryptMsg(title), sendCesium.encryptMsg(msg)
) # Configure JSON document to send
sendCesium.sendDocument(finalDoc, outbox) # Send final signed document
def delete(self, idsMsgList, outbox): def delete(self, idsMsgList, outbox):
deleteCesium = DeleteFromCesium(self.dunikey, self.pod) deleteCesium = DeleteFromCesium(self.dunikey, self.pod)
# deleteCesium.issuer = recipient # deleteCesium.issuer = recipient
for idMsg in idsMsgList: for idMsg in idsMsgList:
finalDoc = deleteCesium.configDoc(idMsg, outbox) finalDoc = deleteCesium.configDoc(idMsg, outbox)
@ -41,55 +45,74 @@ class CesiumPlus(CesiumCommon):
#################### Profiles #################### #################### Profiles ####################
def set(self, name=None, description=None, ville=None, adresse=None, position=None, site=None, avatar=None): def set(
setProfile = Profiles(self.dunikey, self.pod) self,
document = setProfile.configDocSet(name, description, ville, adresse, position, site, avatar) name=None,
result = setProfile.sendDocument(document,'set') description=None,
ville=None,
adresse=None,
position=None,
site=None,
avatar=None,
):
setProfile = Profiles(self.dunikey, self.pod)
document = setProfile.configDocSet(
name, description, ville, adresse, position, site, avatar
)
result = setProfile.sendDocument(document, "set")
print(result) print(result)
return result return result
def get(self, profile=None, avatar=None): def get(self, profile=None, avatar=None):
getProfile = Profiles(self.dunikey, self.pod, self.noNeedDunikey) getProfile = Profiles(self.dunikey, self.pod, self.noNeedDunikey)
if not profile: if not profile:
profile = self.pubkey profile = self.pubkey
if not re.match(PUBKEY_REGEX, profile) or len(profile) > 45: if not re.match(PUBKEY_REGEX, profile) or len(profile) > 45:
scope = 'title' scope = "title"
else: else:
scope = '_id' scope = "_id"
document = getProfile.configDocGet(profile, scope, avatar) document = getProfile.configDocGet(profile, scope, avatar)
resultJSON = getProfile.sendDocument(document, 'get') resultJSON = getProfile.sendDocument(document, "get")
result = getProfile.parseJSON(resultJSON) result = getProfile.parseJSON(resultJSON)
print(result) print(result)
def getPage(self, page=None, avatar=None): def getPage(self, page=None, avatar=None):
getPage = Pages(self.dunikey, self.pod, self.noNeedDunikey) getPage = Pages(self.dunikey, self.pod, self.noNeedDunikey)
if not page: if not page:
page = self.pubkey page = self.pubkey
if not re.match(PUBKEY_REGEX, page) or len(page) > 45: if not re.match(PUBKEY_REGEX, page) or len(page) > 45:
scope = 'title' scope = "title"
else: else:
scope = '_id' scope = "_id"
document = getPage.configDocGet(page, scope, avatar) document = getPage.configDocGet(page, scope, avatar)
resultJSON = getPage.sendDocument(document, 'get') resultJSON = getPage.sendDocument(document, "get")
result = getPage.parseJSON(resultJSON) result = getPage.parseJSON(resultJSON)
print(result) print(result)
def erase(self): def erase(self):
eraseProfile = Profiles(self.dunikey, self.pod) eraseProfile = Profiles(self.dunikey, self.pod)
document = eraseProfile.configDocErase() document = eraseProfile.configDocErase()
result = eraseProfile.sendDocument(document,'erase') result = eraseProfile.sendDocument(document, "erase")
print(result) print(result)
def geolocProfiles(self, node):
geolocProfiles = GeolocProfiles(self.dunikey, self.pod)
cesiumProfiles = geolocProfiles.getCesiumProfiles()
gvaProfiles = geolocProfiles.getGVAProfiles(node)
result = geolocProfiles.formatProfiles(cesiumProfiles, json.loads(gvaProfiles))
print(json.dumps(result))
#################### Likes #################### #################### Likes ####################
def readLikes(self, profile=False): def readLikes(self, profile=False):
likes = ReadLikes(self.dunikey, self.pod, self.noNeedDunikey) likes = ReadLikes(self.dunikey, self.pod, self.noNeedDunikey)
document = likes.configDoc(profile) document = likes.configDoc(profile)
result = likes.sendDocument(document) result = likes.sendDocument(document)
result = likes.parseResult(result) result = likes.parseResult(result)
@ -97,13 +120,13 @@ class CesiumPlus(CesiumCommon):
print(result) print(result)
def like(self, stars, profile=False): def like(self, stars, profile=False):
likes = SendLikes(self.dunikey, self.pod) likes = SendLikes(self.dunikey, self.pod)
document = likes.configDoc(profile, stars) document = likes.configDoc(profile, stars)
if document: if document:
likes.sendDocument(document, profile) likes.sendDocument(document, profile)
def unLike(self, pubkey, silent=False): def unLike(self, pubkey, silent=False):
likes = UnLikes(self.dunikey, self.pod) likes = UnLikes(self.dunikey, self.pod)
idLike = likes.checkLike(pubkey) idLike = likes.checkLike(pubkey)
if idLike: if idLike:
document = likes.configDoc(idLike) document = likes.configDoc(idLike)
@ -111,26 +134,37 @@ class CesiumPlus(CesiumCommon):
#################### Offer #################### #################### Offer ####################
def setOffer(self, title=None, description=None, city=None, localisation=None, category=None, price=None, picture=None): def setOffer(
setOffer = Offers(self.dunikey, self.pod) self,
document = setOffer.configDocSet(title, description, city, localisation, category, price, picture) title=None,
result = setOffer.sendDocumentSet(document,'set') description=None,
city=None,
location=None,
category=None,
price=None,
picture=None,
):
setOffer = Offers(self.dunikey, self.pod)
document = setOffer.configDocSet(
title, description, city, location, category, price, picture
)
result = setOffer.sendDocumentSet(document, "set")
# print(result) # print(result)
return result return result
def getOffer(self, id, avatar=None): def getOffer(self, id, avatar=None):
getOffer = Offers(self.dunikey, self.pod, self.noNeedDunikey) getOffer = Offers(self.dunikey, self.pod, self.noNeedDunikey)
resultJSON = getOffer.sendDocumentGet(id, 'get') resultJSON = getOffer.sendDocumentGet(id, "get")
# print(resultJSON) # print(resultJSON)
result = getOffer.parseJSON(resultJSON) result = getOffer.parseJSON(resultJSON)
print(result) print(result)
def deleteOffer(self, id): def deleteOffer(self, id):
eraseOffer = Offers(self.dunikey, self.pod) eraseOffer = Offers(self.dunikey, self.pod)
document = eraseOffer.configDocErase(id) document = eraseOffer.configDocErase(id)
result = eraseOffer.sendDocumentSet(document,'delete', id) result = eraseOffer.sendDocumentSet(document, "delete", id)
print(result) print(result)

0
lib/currentUd.py Normal file → Executable file
View File

112
lib/geolocProfiles.py Executable file
View File

@ -0,0 +1,112 @@
import requests
from time import time
from lib.cesiumCommon import CesiumCommon
from lib.gvaWallets import ListWallets
class GeolocProfiles(CesiumCommon):
def getCesiumProfiles(self):
# Send a POST request to the Cesium profiles API
response = requests.post(
"https://g1.data.e-is.pro/user/profile/_search?scroll=2m",
json={
"query": {
"constant_score": {
"filter": [
{"exists": {"field": "geoPoint"}},
{
"geo_bounding_box": {
"geoPoint": {
"top_left": {"lat": 90, "lon": -180},
"bottom_right": {"lat": -90, "lon": 180},
}
}
},
]
}
},
"_source": [
"title",
"avatar._content_type",
"description",
"city",
"address",
"socials.url",
"creationTime",
"membersCount",
"type",
"geoPoint",
],
"size": 20000,
},
)
scroll_id = response.json()["_scroll_id"]
finalResult: dict | None = response.json()["hits"]["hits"]
while True:
# Send a scroll request to get the next page
response_scroll = requests.post(
"https://g1.data.e-is.pro/_search/scroll",
json={"scroll_id": scroll_id, "scroll": "2m"},
)
# Check if the response is empty (no results) or if there's an error
if (
not response_scroll.json()["hits"]["hits"]
or "error" in response_scroll.json()
):
break
else:
finalResult.extend(response_scroll.json()["hits"]["hits"])
# Process the results here
# Delete the scroll context when done
requests.delete(
"https://g1.data.e-is.pro/_search/scroll", json={"scroll_id": [scroll_id]}
)
return finalResult
def getGVAProfiles(self, node):
# Retrieve GVA profiles using the ListWallets class
gva = ListWallets(node, map=True)
return gva.sendDoc()
def formatProfiles(self, cesiumProfiles, gvaProfiles):
walletsResult = []
for profile in cesiumProfiles:
source: dict = profile["_source"]
pubkey: dict = profile["_id"]
if pubkey not in gvaProfiles:
continue
# Extract necessary information from the profiles
id_info: dict = gvaProfiles[pubkey].get("id") or {}
isMember = id_info.get("isMember", False)
userId = id_info.get("username")
title = source.get("title")
city = source.get("city")
avatar = source.get("avatar")
socials = source.get("socials")
description = source.get("description")
address = source.get("address")
walletsResult.append(
{
"pubkey": pubkey,
**({"address": address} if address else {}),
**({"city": city} if city else {}),
**({"description": description} if description else {}),
**({"avatar": avatar} if avatar else {}),
**({"userId": userId} if userId else {}),
"isMember": isMember,
"geoPoint": source["geoPoint"],
**({"socials": socials} if socials else {}),
**({"title": title} if title else {}),
}
)
return {"wallets": walletsResult, "time": int(time())}

0
lib/getPages.py Normal file → Executable file
View File

View File

@ -43,9 +43,11 @@ class History:
node { node {
currency currency
issuers issuers
blockstamp
outputs outputs
comment comment
writtenTime writtenTime
hash
} }
} }
} }
@ -57,13 +59,17 @@ class History:
comment comment
outputs outputs
receivedTime receivedTime
blockstamp
hash
} }
receiving { sending {
currency currency
issuers issuers
comment comment
outputs outputs
receivedTime receivedTime
blockstamp
hash
} }
} }
balance(script: $script) { balance(script: $script) {
@ -119,6 +125,7 @@ class History:
trans[i] = [] trans[i] = []
trans[i].append(direction) trans[i].append(direction)
trans[i].append(transaction['writtenTime']) trans[i].append(transaction['writtenTime'])
if direction == 'SENT': if direction == 'SENT':
trans[i].append(outPubkey) trans[i].append(outPubkey)
amount = int('-' + output.split(':')[0]) amount = int('-' + output.split(':')[0])
@ -133,12 +140,12 @@ class History:
trans[i].append(round(amount/self.UD, 2)) trans[i].append(round(amount/self.UD, 2))
trans[i].append(transaction['comment']) trans[i].append(transaction['comment'])
trans[i].append(base) trans[i].append(base)
trans[i].append(transaction['blockstamp'])
trans[i].append(transaction['hash'])
i += 1 i += 1
# Parse transactions in mempool # Parse transactions in mempool
for direction in self.historyDoc['txsHistoryMp']: for direction, resBc in self.historyDoc['txsHistoryMp'].items():
resBc = []
resBc = self.historyDoc['txsHistoryMp'][direction]
for j, transaction in enumerate(resBc): for j, transaction in enumerate(resBc):
# print(transaction) # print(transaction)
transaction = resBc[j] transaction = resBc[j]
@ -147,9 +154,11 @@ class History:
# if direction == 'RECEIVING' or self.pubkey != outPubkey: # if direction == 'RECEIVING' or self.pubkey != outPubkey:
trans.append(i) trans.append(i)
trans[i] = [] trans[i] = []
trans[i].append(direction) trans[i].append(direction.upper())
trans[i].append(int(time.time())) trans[i].append(transaction['receivedTime'])
if direction == 'SENDING':
# trans[i].append(int(time.time()))
if direction.upper() == 'SENDING':
trans[i].append(outPubkey) trans[i].append(outPubkey)
amount = int('-' + output.split(':')[0]) amount = int('-' + output.split(':')[0])
else: else:
@ -163,6 +172,8 @@ class History:
trans[i].append(round(amount/self.UD, 2)) trans[i].append(round(amount/self.UD, 2))
trans[i].append(transaction['comment']) trans[i].append(transaction['comment'])
trans[i].append(base) trans[i].append(base)
trans[i].append(transaction['blockstamp'])
trans[i].append(transaction['hash'])
i += 1 i += 1
# Order transactions by date # Order transactions by date
@ -257,11 +268,14 @@ class History:
for i, trans in enumerate(transList): for i, trans in enumerate(transList):
dailyJSON.append(i) dailyJSON.append(i)
dailyJSON[i] = {} dailyJSON[i] = {}
dailyJSON[i]['status'] = trans[0].upper()
dailyJSON[i]['date'] = trans[1] dailyJSON[i]['date'] = trans[1]
dailyJSON[i]['pubkey'] = trans[2] dailyJSON[i]['pubkey'] = trans[2]
dailyJSON[i]['amount'] = trans[3] dailyJSON[i]['amount'] = trans[3]
dailyJSON[i]['amountUD'] = trans[4] dailyJSON[i]['amountUD'] = trans[4]
dailyJSON[i]['comment'] = trans[5] dailyJSON[i]['comment'] = trans[5]
dailyJSON[i]['blockstamp'] = trans[7]
dailyJSON[i]['hash'] = trans[8]
dailyJSON = json.dumps(dailyJSON, indent=2) dailyJSON = json.dumps(dailyJSON, indent=2)
# If we want to write JSON to a file # If we want to write JSON to a file

0
lib/gvaID.py Normal file → Executable file
View File

79
lib/gvaWallets.py Normal file → Executable file
View File

@ -1,27 +1,29 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import sys, re, os.path, json, ast import sys
from termcolor import colored import json
from lib.natools import fmt, sign, get_privkey
from gql import gql, Client from gql import gql, Client
from gql.transport.aiohttp import AIOHTTPTransport from gql.transport.aiohttp import AIOHTTPTransport
from lib.natools import fmt, sign, get_privkey
PUBKEY_REGEX = "(?![OIl])[1-9A-Za-z]{42,45}"
class ListWallets: class ListWallets:
def __init__(
self, node=False, brut=False, mbr=False, nonMbr=False, larf=False, map=False
):
# Initialize the ListWallets class with optional filters
self.mbr = mbr # Filter for members
self.larf = larf # Filter for non-empty identities
self.nonMbr = nonMbr # Filter for non-members
self.brut = brut # Output format flag (brut or JSON)
self.map = map # Output format flag (map or list)
def __init__(self, node, brut, mbr, nonMbr, larf):
self.mbr = mbr
self.larf = larf
self.nonMbr = nonMbr
self.brut = brut
# Define Duniter GVA node # Define Duniter GVA node
transport = AIOHTTPTransport(url=node) transport = AIOHTTPTransport(url=node)
self.client = Client(transport=transport, fetch_schema_from_transport=True) self.client = Client(transport=transport, fetch_schema_from_transport=True)
def sendDoc(self): def sendDoc(self):
# Build wallets generation document # Define the GraphQL query to retrieve wallet information
queryBuild = gql( queryBuild = gql(
""" """
{ {
@ -45,33 +47,54 @@ class ListWallets:
} }
} }
} }
""") """
)
# Send wallets document
try: try:
# Execute the GraphQL query
queryResult = self.client.execute(queryBuild) queryResult = self.client.execute(queryBuild)
except Exception as e: except Exception as e:
sys.stderr.write("Echec de récupération de la liste:\n" + str(e) + "\n") # Handle any exceptions that occur during the query
sys.stderr.write("Failed to retrieve the list:\n" + str(e) + "\n")
sys.exit(1) sys.exit(1)
jsonBrut = queryResult['wallets']['edges'] jsonBrut = queryResult["wallets"]["edges"]
walletList = [] walletList = []
walletMap = {}
for i, trans in enumerate(jsonBrut): for i, trans in enumerate(jsonBrut):
dataWork = trans['node'] dataWork = trans["node"]
if (self.mbr and (dataWork['idty'] == None or dataWork['idty']['isMember'] == False)): continue identity = dataWork["idty"]
if (self.nonMbr and (dataWork['idty'] == None or dataWork['idty']['isMember'] == True)): continue is_member = identity and identity["isMember"]
if (self.larf and (dataWork['idty'] != None)): continue
walletList.append({'pubkey': dataWork['script'],'balance': dataWork['balance']['amount']/100,'id': dataWork['idty']})
if (self.brut): # Apply filters based on member status and larf flag
names = [] member_filter = self.mbr and not is_member
for dataWork in walletList: non_member_filter = self.nonMbr and is_member
if (self.mbr or self.nonMbr): larf_filter = self.larf and identity
names.append(dataWork['pubkey'] + ' ' + dataWork['id']['username']) if member_filter or non_member_filter or larf_filter:
else: continue
names.append(dataWork['pubkey'])
wallet_data = {
"pubkey": dataWork["script"],
"balance": dataWork["balance"]["amount"] / 100,
"id": identity,
}
if self.map:
walletMap[dataWork["script"]] = wallet_data
else:
walletList.append(wallet_data)
if self.brut:
# Generate a list of formatted wallet names using list comprehension
names = [
wallet["pubkey"]
if not (self.mbr or self.nonMbr) or wallet["id"] is None
else f'{wallet["pubkey"]} {wallet["id"]["username"]}'
for wallet in walletList
]
return "\n".join(names) return "\n".join(names)
else: else:
return json.dumps(walletList, indent=2) # Return JSON data in either map or list format
return json.dumps(walletMap if self.map else walletList, indent=2)

8
lib/offers.py Normal file → Executable file
View File

@ -4,7 +4,7 @@ from lib.cesiumCommon import CesiumCommon, PUBKEY_REGEX
class Offers(CesiumCommon): class Offers(CesiumCommon):
# Configure JSON document SET to send # Configure JSON document SET to send
def configDocSet(self, title, description, city, localisation, category, price: float, picture): def configDocSet(self, title, description, city, location, category, price: float, picture):
timeSent = int(time()) timeSent = int(time())
# {"parent":"cat90","localizedNames":{"en":"Fruits & Vegetables","es-ES":"Frutas y Vegetales","fr-FR":"Fruits & Légumes"},"name":"Fruits & Légumes","id":"cat92"} # {"parent":"cat90","localizedNames":{"en":"Fruits & Vegetables","es-ES":"Frutas y Vegetales","fr-FR":"Fruits & Légumes"},"name":"Fruits & Légumes","id":"cat92"}
@ -13,10 +13,10 @@ class Offers(CesiumCommon):
if title: data['title'] = title if title: data['title'] = title
if description: data['description'] = description if description: data['description'] = description
if city: data['city'] = city if city: data['city'] = city
if localisation: if location:
geoPoint = {} geoPoint = {}
geoPoint['lat'] = localisation[0] geoPoint['lat'] = location[0]
geoPoint['lon'] = localisation[1] geoPoint['lon'] = location[1]
data['geoPoint'] = geoPoint data['geoPoint'] = geoPoint
if picture: if picture:
picture = open(picture, 'rb').read() picture = open(picture, 'rb').read()

View File

@ -1,4 +1,4 @@
import sys, re, json, requests, base64 import sys, json, requests, base64
from time import time from time import time
from lib.cesiumCommon import CesiumCommon, PUBKEY_REGEX from lib.cesiumCommon import CesiumCommon, PUBKEY_REGEX
@ -9,71 +9,74 @@ class Profiles(CesiumCommon):
timeSent = int(time()) timeSent = int(time())
data = {} data = {}
if name: data['title'] = name if name:
if description: data['description'] = description data["title"] = name
if address: data['address'] = address if description:
if city: data['city'] = city data["description"] = description
if pos: if address:
data["address"] = address
if city:
data["city"] = city
if pos:
geoPoint = {} geoPoint = {}
geoPoint['lat'] = pos[0] geoPoint["lat"] = pos[0]
geoPoint['lon'] = pos[1] geoPoint["lon"] = pos[1]
data['geoPoint'] = geoPoint data["geoPoint"] = geoPoint
if socials: if socials:
data['socials'] = [] data["socials"] = []
data['socials'].append({}) data["socials"].append({})
data['socials'][0]['type'] = "web" data["socials"][0]["type"] = "web"
data['socials'][0]['url'] = socials data["socials"][0]["url"] = socials
if avatar: if avatar:
avatar = open(avatar, 'rb').read() avatar = open(avatar, "rb").read()
avatar = base64.b64encode(avatar).decode() avatar = base64.b64encode(avatar).decode()
data['avatar'] = {} data["avatar"] = {}
data['avatar']['_content'] = avatar data["avatar"]["_content"] = avatar
data['avatar']['_content_type'] = "image/png" data["avatar"]["_content_type"] = "image/png"
data['time'] = timeSent data["time"] = timeSent
data['issuer'] = self.pubkey data["issuer"] = self.pubkey
data['version'] = 2 data["version"] = 2
data['tags'] = [] data["tags"] = []
document = json.dumps(data) document = json.dumps(data)
return self.signDoc(document) return self.signDoc(document)
# Configure JSON document GET to send # Configure JSON document GET to send
def configDocGet(self, profile, scope='title', getAvatar=None): def configDocGet(self, profile, scope="title", getAvatar=None):
if getAvatar: if getAvatar:
avatar = "avatar" avatar = "avatar"
else: else:
avatar = "avatar._content_type" avatar = "avatar._content_type"
data = { data = {
"query": { "query": {
"bool": { "bool": {
"should":[ "should": [
{ {"match": {scope: {"query": profile, "boost": 2}}},
"match":{ {"prefix": {scope: profile}},
scope:{
"query": profile,"boost":2
}
}
},{
"prefix": {scope: profile}
}
] ]
} }
},"highlight": { },
"fields": { "highlight": {"fields": {"title": {}, "tags": {}}},
"title":{}, "from": 0,
"tags":{} "size": 100,
} "_source": [
},"from":0, "title",
"size":100, avatar,
"_source":["title", avatar,"description","city","address","socials.url","creationTime","membersCount","type","geoPoint"], "description",
"indices_boost":{"user":100,"page":1,"group":0.01 "city",
} "address",
"socials.url",
"creationTime",
"membersCount",
"type",
"geoPoint",
],
"indices_boost": {"user": 100, "page": 1, "group": 0.01},
} }
document = json.dumps(data) document = json.dumps(data)
return document return document
@ -82,44 +85,45 @@ class Profiles(CesiumCommon):
timeSent = int(time()) timeSent = int(time())
data = {} data = {}
data['time'] = timeSent data["time"] = timeSent
data['id'] = self.pubkey data["id"] = self.pubkey
data['issuer'] = self.pubkey data["issuer"] = self.pubkey
data['version'] = 2 data["version"] = 2
data['index'] = "user" data["index"] = "user"
data['type'] = "profile" data["type"] = "profile"
document = json.dumps(data) document = json.dumps(data)
return self.signDoc(document) return self.signDoc(document)
def sendDocument(self, document, type): def sendDocument(self, document, type):
headers = { headers = {
'Content-type': 'application/json', "Content-type": "application/json",
} }
# Send JSON document and get JSON result # Send JSON document and get JSON result
if type == 'set': if type == "set":
reqQuery = '{0}/user/profile?pubkey={1}/_update?pubkey={1}'.format(self.pod, self.pubkey) reqQuery = "{0}/user/profile?pubkey={1}/_update?pubkey={1}".format(
elif type == 'get': self.pod, self.pubkey
reqQuery = '{0}/user,page,group/profile,record/_search'.format(self.pod) )
elif type == 'erase': elif type == "get":
reqQuery = '{0}/history/delete'.format(self.pod) reqQuery = "{0}/user,page,group/profile,record/_search".format(self.pod)
elif type == "erase":
reqQuery = "{0}/history/delete".format(self.pod)
result = requests.post(reqQuery, headers=headers, data=document) result = requests.post(reqQuery, headers=headers, data=document)
if result.status_code == 200: if result.status_code == 200:
# print(result.text) # print(result.text)
return result.text return result.text
else: else:
sys.stderr.write("Echec de l'envoi du document...\n" + result.text + '\n') sys.stderr.write("Echec de l'envoi du document...\n" + result.text + "\n")
def parseJSON(self, doc): def parseJSON(self, doc):
doc = json.loads(doc)['hits']['hits'] doc = json.loads(doc)["hits"]["hits"]
if doc: if doc:
pubkey = { "pubkey": doc[0]['_id'] } pubkey = {"pubkey": doc[0]["_id"]}
rest = doc[0]['_source'] rest = doc[0]["_source"]
final = {**pubkey, **rest} final = {**pubkey, **rest}
return json.dumps(final, indent=2) return json.dumps(final, indent=2)
else: else:
return 'Profile vide' return "Profile vide"

View File

@ -1,9 +1,8 @@
wheel wheel
base58 base58
pybase64 pybase64
duniterpy==0.62.0 duniterpy
termcolor termcolor
python-dotenv python-dotenv
gql==3.0.0a5 gql
#gql==2.0
requests requests

View File

@ -12,7 +12,7 @@ done
pip3 install -r requirements.txt || hasError=1 pip3 install -r requirements.txt || hasError=1
chmod u+x jaklis.py chmod u+x jaklis.py
ln -sf $(realpath jaklis.py) /usr/local/bin/jaklis || hasError=1 sudo ln -sf $(realpath jaklis.py) /usr/local/bin/jaklis || hasError=1
if [[ hasError -eq 0 ]]; then if [[ hasError -eq 0 ]]; then
echo "Setup done. You can use 'jaklis' command, try it." echo "Setup done. You can use 'jaklis' command, try it."