Skip to content

Commit

Permalink
Feat/config file (#34)
Browse files Browse the repository at this point in the history
* firest commit config file

* implementing configfiles part 2 -> added priorit and moved logic to CliUser class

* added testing for configfiles

* Update src/sxapi/cli/example-config.conf

Co-authored-by: Florian Klien <flowolf@klienux.org>

* Update src/sxapi/cli/example-config.conf

Co-authored-by: Florian Klien <flowolf@klienux.org>

* Update tests/cli_tests/test-config.conf

Co-authored-by: Florian Klien <flowolf@klienux.org>

* Update tests/cli_tests/test-config_param.conf

Co-authored-by: Florian Klien <flowolf@klienux.org>

* Update tests/cli_tests/test_cli.py

Co-authored-by: Florian Klien <flowolf@klienux.org>

* Update tests/cli_tests/test_cli.py

Co-authored-by: Florian Klien <flowolf@klienux.org>

* Update tests/cli_tests/test_cli.py

Co-authored-by: Florian Klien <flowolf@klienux.org>

* Update tests/cli_tests/test_cli.py

Co-authored-by: Florian Klien <flowolf@klienux.org>

* renamed cli_user.token to cli_user.api_access_token and renamed env variable name from SMAXTEC_TOKEN to SMAXTEC_API_ACCESS_TOKEN

---------

Co-authored-by: Moser Marco Julian <marco.moser@smaxtec.com>
Co-authored-by: Florian Klien <flowolf@klienux.org>
  • Loading branch information
3 people authored Oct 13, 2023
1 parent 088c1a1 commit 4fa202e
Show file tree
Hide file tree
Showing 12 changed files with 339 additions and 130 deletions.
4 changes: 2 additions & 2 deletions src/sxapi/cli/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
from .credentials import UserCredentials
from .cli_user import CliUser

user_credentials = UserCredentials()
cli_user = CliUser()
111 changes: 83 additions & 28 deletions src/sxapi/cli/cli.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import argparse
import configparser
import os
import sys
from os.path import (
abspath,
expanduser,
)

from setuptools import setup

from sxapi.base import (
IntegrationAPIV2,
PublicAPIV2,
)
from sxapi.cli import user_credentials
from sxapi.cli import cli_user
from sxapi.cli.subparser.get_sensor_data import create_gsd_parser
from sxapi.cli.subparser.token import create_token_parser

Expand All @@ -17,29 +18,71 @@ class Cli:
"""CLI class for handling arguments and calling the API."""

def __init__(self):
self.public_api = None
self.integration_api = None
self.config_file_paths = ["/etc/sxapi.conf", "~/.config/sxapi.conf"]

@staticmethod
def update_config_with_env(config_dict):
config_dict["user"] = os.getenv("SXAPI_USER", config_dict["user"])
config_dict["pwd"] = os.getenv("SXAPI_PASSWORD", config_dict["pwd"])
config_dict["orga"] = os.getenv("SXAPI_ORGA", config_dict["orga"])
config_dict["api_public_v2_path"] = os.getenv(
"SXAPI_API_PUBLIC_V2_PATH", config_dict["api_public_v2_path"]
)
config_dict["api_integration_v2_path"] = os.getenv(
"SXAPI_API_INTEGRATION_V2_PATH", config_dict["api_integration_v2_path"]
)

def read_config_from_file(self, config_file_path):
config_dict = {
"user": None,
"pwd": None,
"orga": None,
"api_public_v2_path": None,
"api_integration_v2_path": None,
}

if config_file_path:
self.config_file_paths.append(config_file_path)

parsable_files = []
for config_file in self.config_file_paths:
config_file = expanduser(config_file)
config_file = abspath(config_file)
parsable_files.append(config_file)

try:
config = configparser.ConfigParser(interpolation=None)
config.read(parsable_files)

config_dict["user"] = config.get("SXAPI", "USER")
config_dict["pwd"] = config.get("SXAPI", "PASSWORD")
config_dict["orga"] = config.get("SXAPI", "ORGA")
config_dict["api_public_v2_path"] = config.get(
"SXAPI", "API_PUBLIC_V2_PATH"
)
config_dict["api_integration_v2_path"] = config.get(
"SXAPI", "API_INTEGRATION_V2_PATH"
)
except (
KeyError,
configparser.NoSectionError,
configparser.MissingSectionHeaderError,
) as e:
if config_file_path:
print(f"Error while reading config file: {e}")
return
# we should raise custom exception here

return config_dict

@staticmethod
def api_status():
"""
Print online status of api/v2 and integration/v2
"""

# TODO: this part is just a hacky trick, this should be moved
# when its finalized where to locate them!!!
email = os.environ.get("SMAXTEC_USER")
password = os.environ.get("SMAXTEC_PASSWORD")
api_token = os.environ.get("SMAXTEC_TOKEN")

public_api = PublicAPIV2(email=email, password=password, api_token=api_token)
integration_api = IntegrationAPIV2(
email=email, password=password, api_token=api_token
)
# hacky part end

pub_resp = public_api.get("/service/status")
int_resp = integration_api.get("/service/status")
pub_resp = cli_user.public_v2_api.get("/service/status")
int_resp = cli_user.integration_v2_api.get("/service/status")

exit_code = 0

Expand Down Expand Up @@ -72,14 +115,12 @@ def parse_args(args):
default=False,
help="print version info and exit.",
)

main_parser.add_argument(
"--status",
action="store_true",
default=False,
help="prints status of api/V2 and integration/v2",
)

main_parser.add_argument(
"-t",
"--arg_token",
Expand All @@ -92,6 +133,14 @@ def parse_args(args):
action="store_true",
help="Use keyring as token source!",
)
main_parser.add_argument(
"-c", "--configfile", type=str, help="Path to config file"
)
main_parser.add_argument(
"--print-configfile",
action="store_true",
help="Print example config file and exits",
)

# gsd_parser
subparsers = main_parser.add_subparsers(help="sub-command help")
Expand All @@ -109,6 +158,17 @@ def run(self):
if not args:
return 0

if args.print_configfile:
with open("./src/sxapi/cli/example-config.conf", "r") as f:
print(f.read())
return

config_dict = self.read_config_from_file(args.configfile or None)

self.update_config_with_env(config_dict)

cli_user.init_user(config_dict, args.arg_token, args.use_keyring)

if args.status:
self.api_status()

Expand All @@ -119,11 +179,6 @@ def run(self):
print("Choose either -k (keyring), -t (argument) or no flag (environment)!")
return

if args.use_keyring:
user_credentials.token = user_credentials.get_token_keyring()
elif args.arg_token:
user_credentials.token = args.arg_token

# run set_defaults for subparser
if hasattr(args, "func"):
args.func(args)
Expand Down
111 changes: 111 additions & 0 deletions src/sxapi/cli/cli_user.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import os

import keyring

from sxapi.base import (
IntegrationAPIV2,
PublicAPIV2,
)


class CliUser:
"""
CliUser class used for initializing, storing, retrieving and deleting
credentials and creating/holding Instances of supported API
Client.
This class should only be used in the cli package.
"""

def __init__(self):
"""
Basic User Credentials Constructor
calls self._init_creds() to set available credentials on startup.
"""

self.api_access_token = None
self.public_v2_api = None
self.integration_v2_api = None

@staticmethod
def get_token_environment():
"""
Gets token named 'SMAXTEC_API_ACCESS_TOKEN' from the systems' environment.
"""

return os.environ.get("SMAXTEC_API_ACCESS_TOKEN", None)

def set_token_keyring(self, token):
"""
Store the given token in keyring.
"""
keyring.set_password("sxapi", "SMAXTEC_API_ACCESS_TOKEN", token)
self.api_access_token = token

@staticmethod
def get_token_keyring():
"""
Gets the token stored in the keyring.
"""
return keyring.get_password("sxapi", "SMAXTEC_API_ACCESS_TOKEN")

@staticmethod
def clear_token_keyring():
"""
Deletes the token from the keyring.
"""
keyring.delete_password("sxapi", "SMAXTEC_API_ACCESS_TOKEN")

# general functions
def check_credentials_set(self):
"""
Checks if token is already set.
"""
if self.api_access_token is not None:
return True
return False

def init_user(self, config_dict, args_token, args_keyring):
"""
This function retrieves the token from the specified resource
(keyring, environment or args) and initializes clients
of the supported APIs (PublicV2, IntegrationV2).
If no token can be found the token is retrieved via
the username and password.
If username and password are also missing, no credentials get
stored and not API clients are created.
"""
if args_token:
self.api_access_token = args_token
elif args_keyring:
self.api_access_token = self.get_token_keyring()
else:
self.api_access_token = self.get_token_environment()

if self.api_access_token is None and config_dict["user"] and config_dict["pwd"]:
self.public_v2_api = PublicAPIV2(
base_url=config_dict["api_public_v2_path"],
email=config_dict["user"],
password=config_dict["pwd"],
)
self.integration_v2_api = IntegrationAPIV2(
base_url=config_dict["api_integration_v2_path"],
email=config_dict["user"],
password=config_dict["pwd"],
)

self.api_access_token = self.public_v2_api.get_token()

elif self.api_access_token:
self.public_v2_api = PublicAPIV2(
base_url=config_dict["api_public_v2_path"],
api_token=self.api_access_token,
)

self.integration_v2_api = IntegrationAPIV2(
base_url=config_dict["api_integration_v2_path"],
api_token=self.api_access_token,
)
77 changes: 0 additions & 77 deletions src/sxapi/cli/credentials.py

This file was deleted.

16 changes: 16 additions & 0 deletions src/sxapi/cli/example-config.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[SXAPI]

# smaXtec user name
USER = user.name@example.com

# smaXtec password
PASSWORD = "userSecret"

# organisation to retrieve data from
ORGA = smaxtec_organisation_id

# API url for PublicV2
API_PUBLIC_V2_PATH = https://api.smaxtec.com/v2/public

# API url for IntegrationV2
API_INTEGRATION_V2_PATH = https://api.smaxtec.com/v2/integration
Loading

0 comments on commit 4fa202e

Please sign in to comment.