summaryrefslogtreecommitdiff
path: root/api
diff options
context:
space:
mode:
authorFabian Mastenbroek <mail.fabianm@gmail.com>2021-04-25 21:53:42 +0200
committerGitHub <noreply@github.com>2021-04-25 21:53:42 +0200
commit128f76f7fd7c8abb41a3bbbd9f1980cbc20ae7a5 (patch)
treeadd513890005233a7784466797bfe6f5052e9eeb /api
parent128a1db017545597a5c035b7960eb3fd36b5f987 (diff)
parent57b54b59ed74ec37338ae26b3864d051255aba49 (diff)
build: Flatten project structure
This change updates the project structure to become flattened. Previously, the simulator, frontend and API each lived into their own directory. With this change, all modules of the project live in the top-level directory of the repository.
Diffstat (limited to 'api')
-rw-r--r--api/.gitignore18
-rw-r--r--api/.gitlab-ci.yml26
-rw-r--r--api/.pylintrc522
-rw-r--r--api/.style.yapf3
-rw-r--r--api/Dockerfile17
-rw-r--r--api/README.md101
-rwxr-xr-xapi/check.sh1
-rw-r--r--api/conftest.py15
-rwxr-xr-xapi/format.sh1
-rwxr-xr-xapi/main.py188
-rw-r--r--api/misc/artwork/opendc-web-server-component-diagram.pngbin90161 -> 0 bytes
-rw-r--r--api/opendc/__init__.py0
-rw-r--r--api/opendc/api/__init__.py0
-rw-r--r--api/opendc/api/v2/__init__.py0
-rw-r--r--api/opendc/api/v2/paths.json19
-rw-r--r--api/opendc/api/v2/portfolios/__init__.py0
-rw-r--r--api/opendc/api/v2/portfolios/portfolioId/__init__.py0
-rw-r--r--api/opendc/api/v2/portfolios/portfolioId/endpoint.py67
-rw-r--r--api/opendc/api/v2/portfolios/portfolioId/scenarios/__init__.py0
-rw-r--r--api/opendc/api/v2/portfolios/portfolioId/scenarios/endpoint.py49
-rw-r--r--api/opendc/api/v2/portfolios/portfolioId/scenarios/test_endpoint.py125
-rw-r--r--api/opendc/api/v2/portfolios/portfolioId/test_endpoint.py152
-rw-r--r--api/opendc/api/v2/prefabs/__init__.py0
-rw-r--r--api/opendc/api/v2/prefabs/authorizations/__init__.py0
-rw-r--r--api/opendc/api/v2/prefabs/authorizations/endpoint.py22
-rw-r--r--api/opendc/api/v2/prefabs/authorizations/test_endpoint.py71
-rw-r--r--api/opendc/api/v2/prefabs/endpoint.py23
-rw-r--r--api/opendc/api/v2/prefabs/prefabId/__init__.py0
-rw-r--r--api/opendc/api/v2/prefabs/prefabId/endpoint.py50
-rw-r--r--api/opendc/api/v2/prefabs/prefabId/test_endpoint.py145
-rw-r--r--api/opendc/api/v2/prefabs/test_endpoint.py24
-rw-r--r--api/opendc/api/v2/projects/__init__.py0
-rw-r--r--api/opendc/api/v2/projects/endpoint.py32
-rw-r--r--api/opendc/api/v2/projects/projectId/__init__.py0
-rw-r--r--api/opendc/api/v2/projects/projectId/authorizations/__init__.py0
-rw-r--r--api/opendc/api/v2/projects/projectId/authorizations/endpoint.py17
-rw-r--r--api/opendc/api/v2/projects/projectId/authorizations/test_endpoint.py43
-rw-r--r--api/opendc/api/v2/projects/projectId/endpoint.py66
-rw-r--r--api/opendc/api/v2/projects/projectId/portfolios/__init__.py0
-rw-r--r--api/opendc/api/v2/projects/projectId/portfolios/endpoint.py35
-rw-r--r--api/opendc/api/v2/projects/projectId/portfolios/test_endpoint.py85
-rw-r--r--api/opendc/api/v2/projects/projectId/test_endpoint.py122
-rw-r--r--api/opendc/api/v2/projects/projectId/topologies/__init__.py0
-rw-r--r--api/opendc/api/v2/projects/projectId/topologies/endpoint.py31
-rw-r--r--api/opendc/api/v2/projects/projectId/topologies/test_endpoint.py52
-rw-r--r--api/opendc/api/v2/projects/test_endpoint.py25
-rw-r--r--api/opendc/api/v2/scenarios/__init__.py0
-rw-r--r--api/opendc/api/v2/scenarios/scenarioId/__init__.py0
-rw-r--r--api/opendc/api/v2/scenarios/scenarioId/endpoint.py59
-rw-r--r--api/opendc/api/v2/scenarios/scenarioId/test_endpoint.py149
-rw-r--r--api/opendc/api/v2/schedulers/__init__.py0
-rw-r--r--api/opendc/api/v2/schedulers/endpoint.py19
-rw-r--r--api/opendc/api/v2/schedulers/test_endpoint.py2
-rw-r--r--api/opendc/api/v2/topologies/__init__.py0
-rw-r--r--api/opendc/api/v2/topologies/topologyId/__init__.py0
-rw-r--r--api/opendc/api/v2/topologies/topologyId/endpoint.py58
-rw-r--r--api/opendc/api/v2/topologies/topologyId/test_endpoint.py119
-rw-r--r--api/opendc/api/v2/traces/__init__.py0
-rw-r--r--api/opendc/api/v2/traces/endpoint.py10
-rw-r--r--api/opendc/api/v2/traces/test_endpoint.py6
-rw-r--r--api/opendc/api/v2/traces/traceId/__init__.py0
-rw-r--r--api/opendc/api/v2/traces/traceId/endpoint.py14
-rw-r--r--api/opendc/api/v2/traces/traceId/test_endpoint.py15
-rw-r--r--api/opendc/api/v2/users/__init__.py0
-rw-r--r--api/opendc/api/v2/users/endpoint.py30
-rw-r--r--api/opendc/api/v2/users/test_endpoint.py34
-rw-r--r--api/opendc/api/v2/users/userId/__init__.py0
-rw-r--r--api/opendc/api/v2/users/userId/endpoint.py59
-rw-r--r--api/opendc/api/v2/users/userId/test_endpoint.py56
-rw-r--r--api/opendc/models/__init__.py0
-rw-r--r--api/opendc/models/model.py64
-rw-r--r--api/opendc/models/portfolio.py24
-rw-r--r--api/opendc/models/prefab.py28
-rw-r--r--api/opendc/models/project.py31
-rw-r--r--api/opendc/models/scenario.py26
-rw-r--r--api/opendc/models/topology.py27
-rw-r--r--api/opendc/models/trace.py7
-rw-r--r--api/opendc/models/user.py36
-rw-r--r--api/opendc/util/__init__.py0
-rw-r--r--api/opendc/util/database.py77
-rw-r--r--api/opendc/util/exceptions.py64
-rw-r--r--api/opendc/util/json.py12
-rw-r--r--api/opendc/util/parameter_checker.py85
-rw-r--r--api/opendc/util/path_parser.py36
-rw-r--r--api/opendc/util/rest.py141
-rw-r--r--api/pytest.ini5
-rw-r--r--api/requirements.txt47
-rw-r--r--api/static/index.html22
88 files changed, 0 insertions, 3509 deletions
diff --git a/api/.gitignore b/api/.gitignore
deleted file mode 100644
index b0390689..00000000
--- a/api/.gitignore
+++ /dev/null
@@ -1,18 +0,0 @@
-.DS_Store
-*.pyc
-*.pyo
-venv
-venv*
-dist
-build
-*.egg
-*.egg-info
-_mailinglist
-.tox
-.cache/
-.idea/
-config.json
-test.json
-.env*
-.coverage
-.junit-report.xml
diff --git a/api/.gitlab-ci.yml b/api/.gitlab-ci.yml
deleted file mode 100644
index d80ba836..00000000
--- a/api/.gitlab-ci.yml
+++ /dev/null
@@ -1,26 +0,0 @@
-image: "python:3.8"
-
-variables:
- PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip"
-
-cache:
- paths:
- - .cache/pip
-
-stages:
- - static-analysis
- - test
-
-static-analysis:
- stage: static-analysis
- script:
- - python --version
- - pip install -r requirements.txt
- - pylint opendc
-
-test:
- stage: test
- script:
- - python --version
- - pip install -r requirements.txt
- - pytest opendc
diff --git a/api/.pylintrc b/api/.pylintrc
deleted file mode 100644
index 7fe24187..00000000
--- a/api/.pylintrc
+++ /dev/null
@@ -1,522 +0,0 @@
-[MASTER]
-
-# A comma-separated list of package or module names from where C extensions may
-# be loaded. Extensions are loading into the active Python interpreter and may
-# run arbitrary code.
-extension-pkg-whitelist=
-
-# Specify a score threshold to be exceeded before program exits with error.
-fail-under=10
-
-# Add files or directories to the blacklist. They should be base names, not
-# paths.
-ignore=CVS
-
-# Add files or directories matching the regex patterns to the blacklist. The
-# regex matches against base names, not paths.
-ignore-patterns=
-
-# Python code to execute, usually for sys.path manipulation such as
-# pygtk.require().
-#init-hook=
-
-# Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the
-# number of processors available to use.
-jobs=1
-
-# Control the amount of potential inferred values when inferring a single
-# object. This can help the performance when dealing with large functions or
-# complex, nested conditions.
-limit-inference-results=100
-
-# List of plugins (as comma separated values of python module names) to load,
-# usually to register additional checkers.
-load-plugins=
-
-# Pickle collected data for later comparisons.
-persistent=yes
-
-# When enabled, pylint would attempt to guess common misconfiguration and emit
-# user-friendly hints instead of false-positive error messages.
-suggestion-mode=yes
-
-# Allow loading of arbitrary C extensions. Extensions are imported into the
-# active Python interpreter and may run arbitrary code.
-unsafe-load-any-extension=no
-
-
-[MESSAGES CONTROL]
-
-# Only show warnings with the listed confidence levels. Leave empty to show
-# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED.
-confidence=
-
-# Disable the message, report, category or checker with the given id(s). You
-# can either give multiple identifiers separated by comma (,) or put this
-# option multiple times (only on the command line, not in the configuration
-# file where it should appear only once). You can also use "--disable=all" to
-# disable everything first and then reenable specific checks. For example, if
-# you want to run only the similarities checker, you can use "--disable=all
-# --enable=similarities". If you want to run only the classes checker, but have
-# no Warning level messages displayed, use "--disable=all --enable=classes
-# --disable=W".
-disable=duplicate-code,
- missing-module-docstring,
- invalid-name,
- bare-except,
- too-few-public-methods,
- fixme
-
-# Enable the message, report, category or checker with the given id(s). You can
-# either give multiple identifier separated by comma (,) or put this option
-# multiple time (only on the command line, not in the configuration file where
-# it should appear only once). See also the "--disable" option for examples.
-enable=c-extension-no-member
-
-
-[REPORTS]
-
-# Python expression which should return a score less than or equal to 10. You
-# have access to the variables 'error', 'warning', 'refactor', and 'convention'
-# which contain the number of messages in each category, as well as 'statement'
-# which is the total number of statements analyzed. This score is used by the
-# global evaluation report (RP0004).
-evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
-
-# Template used to display messages. This is a python new-style format string
-# used to format the message information. See doc for all details.
-#msg-template=
-
-# Set the output format. Available formats are text, parseable, colorized, json
-# and msvs (visual studio). You can also give a reporter class, e.g.
-# mypackage.mymodule.MyReporterClass.
-output-format=text
-
-# Tells whether to display a full report or only the messages.
-reports=no
-
-# Activate the evaluation score.
-score=yes
-
-
-[REFACTORING]
-
-# Maximum number of nested blocks for function / method body
-max-nested-blocks=5
-
-# Complete name of functions that never returns. When checking for
-# inconsistent-return-statements if a never returning function is called then
-# it will be considered as an explicit return statement and no message will be
-# printed.
-never-returning-functions=sys.exit
-
-
-[LOGGING]
-
-# The type of string formatting that logging methods do. `old` means using %
-# formatting, `new` is for `{}` formatting.
-logging-format-style=old
-
-# Logging modules to check that the string format arguments are in logging
-# function parameter format.
-logging-modules=logging
-
-
-[SPELLING]
-
-# Limits count of emitted suggestions for spelling mistakes.
-max-spelling-suggestions=4
-
-# Spelling dictionary name. Available dictionaries: none. To make it work,
-# install the python-enchant package.
-spelling-dict=
-
-# List of comma separated words that should not be checked.
-spelling-ignore-words=
-
-# A path to a file that contains the private dictionary; one word per line.
-spelling-private-dict-file=
-
-# Tells whether to store unknown words to the private dictionary (see the
-# --spelling-private-dict-file option) instead of raising a message.
-spelling-store-unknown-words=no
-
-
-[MISCELLANEOUS]
-
-# List of note tags to take in consideration, separated by a comma.
-notes=FIXME,
- XXX,
- TODO
-
-# Regular expression of note tags to take in consideration.
-#notes-rgx=
-
-
-[TYPECHECK]
-
-# List of decorators that produce context managers, such as
-# contextlib.contextmanager. Add to this list to register other decorators that
-# produce valid context managers.
-contextmanager-decorators=contextlib.contextmanager
-
-# List of members which are set dynamically and missed by pylint inference
-# system, and so shouldn't trigger E1101 when accessed. Python regular
-# expressions are accepted.
-generated-members=
-
-# Tells whether missing members accessed in mixin class should be ignored. A
-# mixin class is detected if its name ends with "mixin" (case insensitive).
-ignore-mixin-members=yes
-
-# Tells whether to warn about missing members when the owner of the attribute
-# is inferred to be None.
-ignore-none=yes
-
-# This flag controls whether pylint should warn about no-member and similar
-# checks whenever an opaque object is returned when inferring. The inference
-# can return multiple potential results while evaluating a Python object, but
-# some branches might not be evaluated, which results in partial inference. In
-# that case, it might be useful to still emit no-member and other checks for
-# the rest of the inferred objects.
-ignore-on-opaque-inference=yes
-
-# List of class names for which member attributes should not be checked (useful
-# for classes with dynamically set attributes). This supports the use of
-# qualified names.
-ignored-classes=optparse.Values,thread._local,_thread._local
-
-# List of module names for which member attributes should not be checked
-# (useful for modules/projects where namespaces are manipulated during runtime
-# and thus existing member attributes cannot be deduced by static analysis). It
-# supports qualified module names, as well as Unix pattern matching.
-ignored-modules=
-
-# Show a hint with possible names when a member name was not found. The aspect
-# of finding the hint is based on edit distance.
-missing-member-hint=yes
-
-# The minimum edit distance a name should have in order to be considered a
-# similar match for a missing member name.
-missing-member-hint-distance=1
-
-# The total number of similar names that should be taken in consideration when
-# showing a hint for a missing member.
-missing-member-max-choices=1
-
-# List of decorators that change the signature of a decorated function.
-signature-mutators=
-
-
-[VARIABLES]
-
-# List of additional names supposed to be defined in builtins. Remember that
-# you should avoid defining new builtins when possible.
-additional-builtins=
-
-# Tells whether unused global variables should be treated as a violation.
-allow-global-unused-variables=yes
-
-# List of strings which can identify a callback function by name. A callback
-# name must start or end with one of those strings.
-callbacks=cb_,
- _cb
-
-# A regular expression matching the name of dummy variables (i.e. expected to
-# not be used).
-dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_
-
-# Argument names that match this expression will be ignored. Default to name
-# with leading underscore.
-ignored-argument-names=_.*|^ignored_|^unused_
-
-# Tells whether we should check for unused import in __init__ files.
-init-import=no
-
-# List of qualified module names which can have objects that can redefine
-# builtins.
-redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io
-
-
-[FORMAT]
-
-# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
-expected-line-ending-format=
-
-# Regexp for a line that is allowed to be longer than the limit.
-ignore-long-lines=^\s*(# )?<?https?://\S+>?$
-
-# Number of spaces of indent required inside a hanging or continued line.
-indent-after-paren=4
-
-# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
-# tab).
-indent-string=' '
-
-# Maximum number of characters on a single line.
-max-line-length=120
-
-# Maximum number of lines in a module.
-max-module-lines=1000
-
-# List of optional constructs for which whitespace checking is disabled. `dict-
-# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}.
-# `trailing-comma` allows a space between comma and closing bracket: (a, ).
-# `empty-line` allows space-only lines.
-no-space-check=trailing-comma,
- dict-separator
-
-# Allow the body of a class to be on the same line as the declaration if body
-# contains single statement.
-single-line-class-stmt=no
-
-# Allow the body of an if to be on the same line as the test if there is no
-# else.
-single-line-if-stmt=no
-
-
-[SIMILARITIES]
-
-# Ignore comments when computing similarities.
-ignore-comments=yes
-
-# Ignore docstrings when computing similarities.
-ignore-docstrings=yes
-
-# Ignore imports when computing similarities.
-ignore-imports=no
-
-# Minimum lines number of a similarity.
-min-similarity-lines=4
-
-
-[BASIC]
-
-# Naming style matching correct argument names.
-argument-naming-style=snake_case
-
-# Regular expression matching correct argument names. Overrides argument-
-# naming-style.
-#argument-rgx=
-
-# Naming style matching correct attribute names.
-attr-naming-style=snake_case
-
-# Regular expression matching correct attribute names. Overrides attr-naming-
-# style.
-#attr-rgx=
-
-# Bad variable names which should always be refused, separated by a comma.
-bad-names=foo,
- bar,
- baz,
- toto,
- tutu,
- tata
-
-# Bad variable names regexes, separated by a comma. If names match any regex,
-# they will always be refused
-bad-names-rgxs=
-
-# Naming style matching correct class attribute names.
-class-attribute-naming-style=any
-
-# Regular expression matching correct class attribute names. Overrides class-
-# attribute-naming-style.
-#class-attribute-rgx=
-
-# Naming style matching correct class names.
-class-naming-style=PascalCase
-
-# Regular expression matching correct class names. Overrides class-naming-
-# style.
-#class-rgx=
-
-# Naming style matching correct constant names.
-const-naming-style=UPPER_CASE
-
-# Regular expression matching correct constant names. Overrides const-naming-
-# style.
-#const-rgx=
-
-# Minimum line length for functions/classes that require docstrings, shorter
-# ones are exempt.
-docstring-min-length=-1
-
-# Naming style matching correct function names.
-function-naming-style=snake_case
-
-# Regular expression matching correct function names. Overrides function-
-# naming-style.
-#function-rgx=
-
-# Good variable names which should always be accepted, separated by a comma.
-good-names=i,
- j,
- k,
- ex,
- Run,
- _
-
-# Good variable names regexes, separated by a comma. If names match any regex,
-# they will always be accepted
-good-names-rgxs=
-
-# Include a hint for the correct naming format with invalid-name.
-include-naming-hint=no
-
-# Naming style matching correct inline iteration names.
-inlinevar-naming-style=any
-
-# Regular expression matching correct inline iteration names. Overrides
-# inlinevar-naming-style.
-#inlinevar-rgx=
-
-# Naming style matching correct method names.
-method-naming-style=snake_case
-
-# Regular expression matching correct method names. Overrides method-naming-
-# style.
-#method-rgx=
-
-# Naming style matching correct module names.
-module-naming-style=snake_case
-
-# Regular expression matching correct module names. Overrides module-naming-
-# style.
-#module-rgx=
-
-# Colon-delimited sets of names that determine each other's naming style when
-# the name regexes allow several styles.
-name-group=
-
-# Regular expression which should only match function or class names that do
-# not require a docstring.
-no-docstring-rgx=^_
-
-# List of decorators that produce properties, such as abc.abstractproperty. Add
-# to this list to register other decorators that produce valid properties.
-# These decorators are taken in consideration only for invalid-name.
-property-classes=abc.abstractproperty
-
-# Naming style matching correct variable names.
-variable-naming-style=snake_case
-
-# Regular expression matching correct variable names. Overrides variable-
-# naming-style.
-#variable-rgx=
-
-
-[STRING]
-
-# This flag controls whether inconsistent-quotes generates a warning when the
-# character used as a quote delimiter is used inconsistently within a module.
-check-quote-consistency=no
-
-# This flag controls whether the implicit-str-concat should generate a warning
-# on implicit string concatenation in sequences defined over several lines.
-check-str-concat-over-line-jumps=no
-
-
-[IMPORTS]
-
-# List of modules that can be imported at any level, not just the top level
-# one.
-allow-any-import-level=
-
-# Allow wildcard imports from modules that define __all__.
-allow-wildcard-with-all=no
-
-# Analyse import fallback blocks. This can be used to support both Python 2 and
-# 3 compatible code, which means that the block might have code that exists
-# only in one or another interpreter, leading to false positives when analysed.
-analyse-fallback-blocks=no
-
-# Deprecated modules which should not be used, separated by a comma.
-deprecated-modules=optparse,tkinter.tix
-
-# Create a graph of external dependencies in the given file (report RP0402 must
-# not be disabled).
-ext-import-graph=
-
-# Create a graph of every (i.e. internal and external) dependencies in the
-# given file (report RP0402 must not be disabled).
-import-graph=
-
-# Create a graph of internal dependencies in the given file (report RP0402 must
-# not be disabled).
-int-import-graph=
-
-# Force import order to recognize a module as part of the standard
-# compatibility libraries.
-known-standard-library=
-
-# Force import order to recognize a module as part of a third party library.
-known-third-party=enchant
-
-# Couples of modules and preferred modules, separated by a comma.
-preferred-modules=
-
-
-[CLASSES]
-
-# List of method names used to declare (i.e. assign) instance attributes.
-defining-attr-methods=__init__,
- __new__,
- setUp,
- __post_init__
-
-# List of member names, which should be excluded from the protected access
-# warning.
-exclude-protected=_asdict,
- _fields,
- _replace,
- _source,
- _make
-
-# List of valid names for the first argument in a class method.
-valid-classmethod-first-arg=cls
-
-# List of valid names for the first argument in a metaclass class method.
-valid-metaclass-classmethod-first-arg=cls
-
-
-[DESIGN]
-
-# Maximum number of arguments for function / method.
-max-args=5
-
-# Maximum number of attributes for a class (see R0902).
-max-attributes=12
-
-# Maximum number of boolean expressions in an if statement (see R0916).
-max-bool-expr=5
-
-# Maximum number of branch for function / method body.
-max-branches=12
-
-# Maximum number of locals for function / method body.
-max-locals=15
-
-# Maximum number of parents for a class (see R0901).
-max-parents=7
-
-# Maximum number of public methods for a class (see R0904).
-max-public-methods=20
-
-# Maximum number of return / yield for function / method body.
-max-returns=6
-
-# Maximum number of statements in function / method body.
-max-statements=50
-
-# Minimum number of public methods for a class (see R0903).
-min-public-methods=2
-
-
-[EXCEPTIONS]
-
-# Exceptions that will emit a warning when being caught. Defaults to
-# "BaseException, Exception".
-overgeneral-exceptions=BaseException,
- Exception
diff --git a/api/.style.yapf b/api/.style.yapf
deleted file mode 100644
index f5c26c57..00000000
--- a/api/.style.yapf
+++ /dev/null
@@ -1,3 +0,0 @@
-[style]
-based_on_style = pep8
-column_limit=120
diff --git a/api/Dockerfile b/api/Dockerfile
deleted file mode 100644
index 49702c90..00000000
--- a/api/Dockerfile
+++ /dev/null
@@ -1,17 +0,0 @@
-FROM python:3.8
-MAINTAINER OpenDC Maintainers <opendc@atlarge-research.com>
-
-# Ensure the STDOUT is not buffered by Python so that our logs become visible
-# See https://stackoverflow.com/q/29663459/10213073
-ENV PYTHONUNBUFFERED 1
-
-# Copy OpenDC directory
-COPY ./ /opendc
-
-# Fetch web server dependencies
-RUN pip install -r /opendc/requirements.txt
-
-# Set working directory
-WORKDIR /opendc
-
-CMD ["python3", "main.py"]
diff --git a/api/README.md b/api/README.md
deleted file mode 100644
index 182cd803..00000000
--- a/api/README.md
+++ /dev/null
@@ -1,101 +0,0 @@
-<h1 align="center">
- <img src="../misc/artwork/logo.png" width="100" alt="OpenDC">
- <br>
- OpenDC Web Server
-</h1>
-<p align="center">
- Collaborative Datacenter Simulation and Exploration for Everybody
-</p>
-
-<br>
-
-The OpenDC web server is the bridge between OpenDC's frontend and database. It is built with Flask/SocketIO in Python and implements the OpenAPI-compliant [OpenDC API specification](../opendc-api-spec.yml).
-
-This document explains a high-level view of the web server architecture ([jump](#architecture)), and describes how to set up the web server for local development ([jump](#setup-for-local-development)).
-
-## Architecture
-
-The following diagram shows a high-level view of the architecture of the OpenDC web server. Squared-off colored boxes indicate packages (colors become more saturated as packages are nested); rounded-off boxes indicate individual components; dotted lines indicate control flow; and solid lines indicate data flow.
-
-![OpenDC Web Server Component Diagram](misc/artwork/opendc-web-server-component-diagram.png)
-
-The OpenDC API is implemented by the `Main Server Loop`, which is the only component in the base package.
-
-### Util Package
-
-The `Util` package handles several miscellaneous tasks:
-
-* `Database API`: Wraps database access functionality used by `Models` to read themselves from/write themselves into the database.
-* `Exceptions`: Holds definitions for exceptions used throughout the web server.
-* `Parameter Checker`: Recursively checks whether required `Request` parameters are present and correctly typed.
-* `REST`: Parses SocketIO and HTTP messages into `Request` objects, and calls the appropriate `API` endpoint to get a `Response` object to return to the `Main Server Loop`.
-
-### API Package
-
-The `API` package contains the logic for the HTTP methods in each API endpoint. Packages are structured to mirror the API: the code for the endpoint `GET api/projects`, for example, would be located at the `endpoint.py` inside the `projects` package (so at `api/projects/endpoint.py`).
-
-An `endpoint.py` file contains methods for each HTTP method it supports, which takes a request as input (such as `def GET(request):`). Typically, such a method checks whether the parameters were passed correctly (using the `Parameter Checker`); fetches some model from the database; checks whether the data exists and is accessible by the user who made the request; possibly modifies this data and writes it back to the database; and returns a JSON representation of the model.
-
-The `REST` component dynamically imports the appropriate method from the appropriate `endpoint`, according to request it receives, and executes it.
-
-### Models Package
-
-The `models` package contains the logic for mapping Python objects to their database representations. This involves an abstract `model` which has generic CRUD operations. Extensions of `model`, such as a `User` or `Project`, specify some more specific operations and their collection metadata.
-
-`Endpoint`s import these `models` and use them to execute requests.
-
-## Setup for Local Development
-
-The following steps will guide you through setting up the OpenDC web server locally for development. To test individual endpoints, edit `static/index.html`.
-
-### Local Setup
-
-#### Install requirements
-
-Make sure you have Python 3.7+ installed (if not, get it [here](https://www.python.org/)), as well as pip (if not, get it [here](https://pip.pypa.io/en/stable/installing/)). Then run the following to install the requirements.
-
-```bash
-pip install -r requirements.txt
-```
-
-The web server also requires a running MongoDB instance. We recommend setting this up through docker, by running `docker-compose build` and `docker-compose up` in the [`mongodb` directory](../database) of the main OpenDC repository.
-
-#### Get and configure the code
-
-Clone OpenDC and follow the [instructions in the main repository](../) to set up a Google OAuth ID and environment variables.
-
-**Important:** Be sure to set up environment variables according to those instructions, in a `.env` file.
-
-If you want to test REST calls manually, add your own `OAUTH_CLIENT_ID` in `content=` on line `2` in `api/static/index.html`.
-
-#### Set up the database
-
-You can selectively run only the database services from the standard OpenDC `docker-compose` setup (in the root directory):
-
-```bash
-docker-compose build mongo mongo-express
-docker-compose up mongo mongo-express
-```
-
-This will set you up with a running MongoDB instance and a visual inspection tool running on [localhost:8082](http://localhost:8082), with which you can view and manipulate the database. Add the simulator images to the command lists above if you want to test simulation capabilities, as well.
-
-### Local Development
-
-Run the server.
-
-```bash
-cd api
-python main.py
-```
-
-When editing the web server code, restart the server (`CTRL` + `c` followed by `python main.py` in the console running the server) to see the result of your changes.
-
-#### Code Style
-
-To format all files, run `format.sh` in this directory. The script uses `yapf` internally to format everything automatically.
-
-To check if code style is up to modern standards, run `check.sh` in this directory. The script uses `pylint` internally.
-
-#### Testing
-
-Run `pytest opendc` in this directory to run all tests.
diff --git a/api/check.sh b/api/check.sh
deleted file mode 100755
index abe2c596..00000000
--- a/api/check.sh
+++ /dev/null
@@ -1 +0,0 @@
-pylint opendc --ignore-patterns=test_.*?py
diff --git a/api/conftest.py b/api/conftest.py
deleted file mode 100644
index 1f4831b8..00000000
--- a/api/conftest.py
+++ /dev/null
@@ -1,15 +0,0 @@
-"""
-Configuration file for all unit tests.
-"""
-import pytest
-
-from main import FLASK_CORE_APP
-
-
-@pytest.fixture
-def client():
- """Returns a Flask API client to interact with."""
- FLASK_CORE_APP.config['TESTING'] = True
-
- with FLASK_CORE_APP.test_client() as client:
- yield client
diff --git a/api/format.sh b/api/format.sh
deleted file mode 100755
index 18cba452..00000000
--- a/api/format.sh
+++ /dev/null
@@ -1 +0,0 @@
-yapf **/*.py -i
diff --git a/api/main.py b/api/main.py
deleted file mode 100755
index 5c6dac31..00000000
--- a/api/main.py
+++ /dev/null
@@ -1,188 +0,0 @@
-#!/usr/bin/env python3
-import json
-import os
-import sys
-import traceback
-import urllib.request
-
-import flask_socketio
-from dotenv import load_dotenv
-from flask import Flask, request, jsonify
-from flask_compress import Compress
-from flask_cors import CORS
-from oauth2client import client, crypt
-
-from opendc.models.user import User
-from opendc.util import rest, path_parser, database
-from opendc.util.exceptions import AuthorizationTokenError, RequestInitializationError
-from opendc.util.json import JSONEncoder
-
-load_dotenv()
-
-TEST_MODE = "OPENDC_FLASK_TESTING" in os.environ
-
-# Setup Sentry if DSN is specified
-if 'SENTRY_DSN' in os.environ:
- import sentry_sdk
- from sentry_sdk.integrations.flask import FlaskIntegration
-
- sentry_sdk.init(
- integrations=[FlaskIntegration()],
- traces_sample_rate=0.1
- )
-
-# Set up database if not testing
-if not TEST_MODE:
- database.DB.initialize_database(
- user=os.environ['OPENDC_DB_USERNAME'],
- password=os.environ['OPENDC_DB_PASSWORD'],
- database=os.environ['OPENDC_DB'],
- host=os.environ.get('OPENDC_DB_HOST', 'localhost'))
-
-# Set up the core app
-FLASK_CORE_APP = Flask(__name__)
-FLASK_CORE_APP.testing = TEST_MODE
-FLASK_CORE_APP.config['SECRET_KEY'] = os.environ['OPENDC_FLASK_SECRET']
-FLASK_CORE_APP.json_encoder = JSONEncoder
-
-# Set up CORS support
-CORS(FLASK_CORE_APP)
-
-compress = Compress()
-compress.init_app(FLASK_CORE_APP)
-
-SOCKET_IO_CORE = flask_socketio.SocketIO(FLASK_CORE_APP, cors_allowed_origins="*")
-
-API_VERSIONS = {'v2'}
-
-
-@FLASK_CORE_APP.route('/tokensignin', methods=['POST'])
-def sign_in():
- """Authenticate a user with Google sign in"""
-
- try:
- token = request.form['idtoken']
- except KeyError:
- return 'No idtoken provided', 401
-
- try:
- idinfo = client.verify_id_token(token, os.environ['OPENDC_OAUTH_CLIENT_ID'])
-
- if idinfo['aud'] != os.environ['OPENDC_OAUTH_CLIENT_ID']:
- raise crypt.AppIdentityError('Unrecognized client.')
-
- if idinfo['iss'] not in ['accounts.google.com', 'https://accounts.google.com']:
- raise crypt.AppIdentityError('Wrong issuer.')
- except ValueError:
- url = "https://www.googleapis.com/oauth2/v3/tokeninfo?id_token={}".format(token)
- req = urllib.request.Request(url)
- response = urllib.request.urlopen(url=req, timeout=30)
- res = response.read()
- idinfo = json.loads(res)
- except crypt.AppIdentityError as e:
- return 'Did not successfully authenticate'
-
- user = User.from_google_id(idinfo['sub'])
-
- data = {'isNewUser': user.obj is None}
-
- if user.obj is not None:
- data['userId'] = user.get_id()
-
- return jsonify(**data)
-
-
-@FLASK_CORE_APP.route('/<string:version>/<path:endpoint_path>', methods=['GET', 'POST', 'PUT', 'DELETE'])
-def api_call(version, endpoint_path):
- """Call an API endpoint directly over HTTP."""
-
- # Check whether given version is valid
- if version not in API_VERSIONS:
- return jsonify(error='API version not found'), 404
-
- # Get path and parameters
- (path, path_parameters) = path_parser.parse(version, endpoint_path)
-
- query_parameters = request.args.to_dict()
- for param in query_parameters:
- try:
- query_parameters[param] = int(query_parameters[param])
- except:
- pass
-
- try:
- body_parameters = json.loads(request.get_data())
- except:
- body_parameters = {}
-
- # Create and call request
- (req, response) = _process_message({
- 'id': 0,
- 'method': request.method,
- 'parameters': {
- 'body': body_parameters,
- 'path': path_parameters,
- 'query': query_parameters
- },
- 'path': path,
- 'token': request.headers.get('auth-token')
- })
-
- print(
- f'HTTP:\t{req.method} to `/{req.path}` resulted in {response.status["code"]}: {response.status["description"]}')
- sys.stdout.flush()
-
- flask_response = jsonify(json.loads(response.to_JSON()))
- flask_response.status_code = response.status['code']
- return flask_response
-
-
-@SOCKET_IO_CORE.on('request')
-def receive_message(message):
- """"Receive a SocketIO request"""
- (req, res) = _process_message(message)
-
- print(f'Socket: {req.method} to `/{req.path}` resulted in {res.status["code"]}: {res.status["description"]}')
- sys.stdout.flush()
-
- flask_socketio.emit('response', res.to_JSON(), json=True)
-
-
-def _process_message(message):
- """Process a request message and return the response."""
-
- try:
- req = rest.Request(message)
- res = req.process()
-
- return req, res
-
- except AuthorizationTokenError:
- res = rest.Response(401, 'Authorization error')
- res.id = message['id']
-
- except RequestInitializationError as e:
- res = rest.Response(400, str(e))
- res.id = message['id']
-
- if not 'method' in message:
- message['method'] = 'UNSPECIFIED'
- if not 'path' in message:
- message['path'] = 'UNSPECIFIED'
-
- except Exception:
- res = rest.Response(500, 'Internal server error')
- if 'id' in message:
- res.id = message['id']
- traceback.print_exc()
-
- req = rest.Request()
- req.method = message['method']
- req.path = message['path']
-
- return req, res
-
-
-if __name__ == '__main__':
- print("Web server started on 8081")
- SOCKET_IO_CORE.run(FLASK_CORE_APP, host='0.0.0.0', port=8081, use_reloader=False)
diff --git a/api/misc/artwork/opendc-web-server-component-diagram.png b/api/misc/artwork/opendc-web-server-component-diagram.png
deleted file mode 100644
index 91b26006..00000000
--- a/api/misc/artwork/opendc-web-server-component-diagram.png
+++ /dev/null
Binary files differ
diff --git a/api/opendc/__init__.py b/api/opendc/__init__.py
deleted file mode 100644
index e69de29b..00000000
--- a/api/opendc/__init__.py
+++ /dev/null
diff --git a/api/opendc/api/__init__.py b/api/opendc/api/__init__.py
deleted file mode 100644
index e69de29b..00000000
--- a/api/opendc/api/__init__.py
+++ /dev/null
diff --git a/api/opendc/api/v2/__init__.py b/api/opendc/api/v2/__init__.py
deleted file mode 100644
index e69de29b..00000000
--- a/api/opendc/api/v2/__init__.py
+++ /dev/null
diff --git a/api/opendc/api/v2/paths.json b/api/opendc/api/v2/paths.json
deleted file mode 100644
index 652be5bc..00000000
--- a/api/opendc/api/v2/paths.json
+++ /dev/null
@@ -1,19 +0,0 @@
-[
- "/users",
- "/users/{userId}",
- "/projects",
- "/projects/{projectId}",
- "/projects/{projectId}/authorizations",
- "/projects/{projectId}/topologies",
- "/projects/{projectId}/portfolios",
- "/topologies/{topologyId}",
- "/portfolios/{portfolioId}",
- "/portfolios/{portfolioId}/scenarios",
- "/scenarios/{scenarioId}",
- "/schedulers",
- "/traces",
- "/traces/{traceId}",
- "/prefabs",
- "/prefabs/{prefabId}",
- "/prefabs/authorizations"
-]
diff --git a/api/opendc/api/v2/portfolios/__init__.py b/api/opendc/api/v2/portfolios/__init__.py
deleted file mode 100644
index e69de29b..00000000
--- a/api/opendc/api/v2/portfolios/__init__.py
+++ /dev/null
diff --git a/api/opendc/api/v2/portfolios/portfolioId/__init__.py b/api/opendc/api/v2/portfolios/portfolioId/__init__.py
deleted file mode 100644
index e69de29b..00000000
--- a/api/opendc/api/v2/portfolios/portfolioId/__init__.py
+++ /dev/null
diff --git a/api/opendc/api/v2/portfolios/portfolioId/endpoint.py b/api/opendc/api/v2/portfolios/portfolioId/endpoint.py
deleted file mode 100644
index 0ba61a13..00000000
--- a/api/opendc/api/v2/portfolios/portfolioId/endpoint.py
+++ /dev/null
@@ -1,67 +0,0 @@
-from opendc.models.portfolio import Portfolio
-from opendc.models.project import Project
-from opendc.util.rest import Response
-
-
-def GET(request):
- """Get this Portfolio."""
-
- request.check_required_parameters(path={'portfolioId': 'string'})
-
- portfolio = Portfolio.from_id(request.params_path['portfolioId'])
-
- portfolio.check_exists()
- portfolio.check_user_access(request.google_id, False)
-
- return Response(200, 'Successfully retrieved portfolio.', portfolio.obj)
-
-
-def PUT(request):
- """Update this Portfolio."""
-
- request.check_required_parameters(path={'portfolioId': 'string'}, body={'portfolio': {
- 'name': 'string',
- 'targets': {
- 'enabledMetrics': 'list',
- 'repeatsPerScenario': 'int',
- },
- }})
-
- portfolio = Portfolio.from_id(request.params_path['portfolioId'])
-
- portfolio.check_exists()
- portfolio.check_user_access(request.google_id, True)
-
- portfolio.set_property('name',
- request.params_body['portfolio']['name'])
- portfolio.set_property('targets.enabledMetrics',
- request.params_body['portfolio']['targets']['enabledMetrics'])
- portfolio.set_property('targets.repeatsPerScenario',
- request.params_body['portfolio']['targets']['repeatsPerScenario'])
-
- portfolio.update()
-
- return Response(200, 'Successfully updated portfolio.', portfolio.obj)
-
-
-def DELETE(request):
- """Delete this Portfolio."""
-
- request.check_required_parameters(path={'portfolioId': 'string'})
-
- portfolio = Portfolio.from_id(request.params_path['portfolioId'])
-
- portfolio.check_exists()
- portfolio.check_user_access(request.google_id, True)
-
- portfolio_id = portfolio.get_id()
-
- project = Project.from_id(portfolio.obj['projectId'])
- project.check_exists()
- if portfolio_id in project.obj['portfolioIds']:
- project.obj['portfolioIds'].remove(portfolio_id)
- project.update()
-
- old_object = portfolio.delete()
-
- return Response(200, 'Successfully deleted portfolio.', old_object)
diff --git a/api/opendc/api/v2/portfolios/portfolioId/scenarios/__init__.py b/api/opendc/api/v2/portfolios/portfolioId/scenarios/__init__.py
deleted file mode 100644
index e69de29b..00000000
--- a/api/opendc/api/v2/portfolios/portfolioId/scenarios/__init__.py
+++ /dev/null
diff --git a/api/opendc/api/v2/portfolios/portfolioId/scenarios/endpoint.py b/api/opendc/api/v2/portfolios/portfolioId/scenarios/endpoint.py
deleted file mode 100644
index 2f042e06..00000000
--- a/api/opendc/api/v2/portfolios/portfolioId/scenarios/endpoint.py
+++ /dev/null
@@ -1,49 +0,0 @@
-from opendc.models.portfolio import Portfolio
-from opendc.models.scenario import Scenario
-from opendc.models.topology import Topology
-from opendc.util.rest import Response
-
-
-def POST(request):
- """Add a new Scenario for this Portfolio."""
-
- request.check_required_parameters(path={'portfolioId': 'string'},
- body={
- 'scenario': {
- 'name': 'string',
- 'trace': {
- 'traceId': 'string',
- 'loadSamplingFraction': 'float',
- },
- 'topology': {
- 'topologyId': 'string',
- },
- 'operational': {
- 'failuresEnabled': 'bool',
- 'performanceInterferenceEnabled': 'bool',
- 'schedulerName': 'string',
- },
- }
- })
-
- portfolio = Portfolio.from_id(request.params_path['portfolioId'])
-
- portfolio.check_exists()
- portfolio.check_user_access(request.google_id, True)
-
- scenario = Scenario(request.params_body['scenario'])
-
- topology = Topology.from_id(scenario.obj['topology']['topologyId'])
- topology.check_exists()
- topology.check_user_access(request.google_id, True)
-
- scenario.set_property('portfolioId', portfolio.get_id())
- scenario.set_property('simulation', {'state': 'QUEUED'})
- scenario.set_property('topology.topologyId', topology.get_id())
-
- scenario.insert()
-
- portfolio.obj['scenarioIds'].append(scenario.get_id())
- portfolio.update()
-
- return Response(200, 'Successfully added Scenario.', scenario.obj)
diff --git a/api/opendc/api/v2/portfolios/portfolioId/scenarios/test_endpoint.py b/api/opendc/api/v2/portfolios/portfolioId/scenarios/test_endpoint.py
deleted file mode 100644
index e5982b7f..00000000
--- a/api/opendc/api/v2/portfolios/portfolioId/scenarios/test_endpoint.py
+++ /dev/null
@@ -1,125 +0,0 @@
-from opendc.util.database import DB
-
-test_id = 24 * '1'
-
-
-def test_add_scenario_missing_parameter(client):
- assert '400' in client.post('/v2/portfolios/1/scenarios').status
-
-
-def test_add_scenario_non_existing_portfolio(client, mocker):
- mocker.patch.object(DB, 'fetch_one', return_value=None)
- assert '404' in client.post(f'/v2/portfolios/{test_id}/scenarios',
- json={
- 'scenario': {
- 'name': 'test',
- 'trace': {
- 'traceId': test_id,
- 'loadSamplingFraction': 1.0,
- },
- 'topology': {
- 'topologyId': test_id,
- },
- 'operational': {
- 'failuresEnabled': True,
- 'performanceInterferenceEnabled': False,
- 'schedulerName': 'DEFAULT',
- },
- }
- }).status
-
-
-def test_add_scenario_not_authorized(client, mocker):
- mocker.patch.object(DB,
- 'fetch_one',
- return_value={
- '_id': test_id,
- 'projectId': test_id,
- 'portfolioId': test_id,
- 'authorizations': [{
- 'projectId': test_id,
- 'authorizationLevel': 'VIEW'
- }]
- })
- assert '403' in client.post(f'/v2/portfolios/{test_id}/scenarios',
- json={
- 'scenario': {
- 'name': 'test',
- 'trace': {
- 'traceId': test_id,
- 'loadSamplingFraction': 1.0,
- },
- 'topology': {
- 'topologyId': test_id,
- },
- 'operational': {
- 'failuresEnabled': True,
- 'performanceInterferenceEnabled': False,
- 'schedulerName': 'DEFAULT',
- },
- }
- }).status
-
-
-def test_add_scenario(client, mocker):
- mocker.patch.object(DB,
- 'fetch_one',
- return_value={
- '_id': test_id,
- 'projectId': test_id,
- 'portfolioId': test_id,
- 'portfolioIds': [test_id],
- 'scenarioIds': [test_id],
- 'authorizations': [{
- 'projectId': test_id,
- 'authorizationLevel': 'EDIT'
- }],
- 'simulation': {
- 'state': 'QUEUED',
- },
- })
- mocker.patch.object(DB,
- 'insert',
- return_value={
- '_id': test_id,
- 'name': 'test',
- 'trace': {
- 'traceId': test_id,
- 'loadSamplingFraction': 1.0,
- },
- 'topology': {
- 'topologyId': test_id,
- },
- 'operational': {
- 'failuresEnabled': True,
- 'performanceInterferenceEnabled': False,
- 'schedulerName': 'DEFAULT',
- },
- 'portfolioId': test_id,
- 'simulationState': {
- 'state': 'QUEUED',
- },
- })
- mocker.patch.object(DB, 'update', return_value=None)
- res = client.post(
- f'/v2/portfolios/{test_id}/scenarios',
- json={
- 'scenario': {
- 'name': 'test',
- 'trace': {
- 'traceId': test_id,
- 'loadSamplingFraction': 1.0,
- },
- 'topology': {
- 'topologyId': test_id,
- },
- 'operational': {
- 'failuresEnabled': True,
- 'performanceInterferenceEnabled': False,
- 'schedulerName': 'DEFAULT',
- },
- }
- })
- assert 'portfolioId' in res.json['content']
- assert 'simulation' in res.json['content']
- assert '200' in res.status
diff --git a/api/opendc/api/v2/portfolios/portfolioId/test_endpoint.py b/api/opendc/api/v2/portfolios/portfolioId/test_endpoint.py
deleted file mode 100644
index 52f71aa4..00000000
--- a/api/opendc/api/v2/portfolios/portfolioId/test_endpoint.py
+++ /dev/null
@@ -1,152 +0,0 @@
-from opendc.util.database import DB
-
-test_id = 24 * '1'
-test_id_2 = 24 * '2'
-
-
-def test_get_portfolio_non_existing(client, mocker):
- mocker.patch.object(DB, 'fetch_one', return_value=None)
- assert '404' in client.get(f'/v2/portfolios/{test_id}').status
-
-
-def test_get_portfolio_no_authorizations(client, mocker):
- mocker.patch.object(DB, 'fetch_one', return_value={'projectId': test_id, 'authorizations': []})
- res = client.get(f'/v2/portfolios/{test_id}')
- assert '403' in res.status
-
-
-def test_get_portfolio_not_authorized(client, mocker):
- mocker.patch.object(DB,
- 'fetch_one',
- return_value={
- 'projectId': test_id,
- '_id': test_id,
- 'authorizations': [{
- 'projectId': test_id_2,
- 'authorizationLevel': 'OWN'
- }]
- })
- res = client.get(f'/v2/portfolios/{test_id}')
- assert '403' in res.status
-
-
-def test_get_portfolio(client, mocker):
- mocker.patch.object(DB,
- 'fetch_one',
- return_value={
- 'projectId': test_id,
- '_id': test_id,
- 'authorizations': [{
- 'projectId': test_id,
- 'authorizationLevel': 'EDIT'
- }]
- })
- res = client.get(f'/v2/portfolios/{test_id}')
- assert '200' in res.status
-
-
-def test_update_portfolio_missing_parameter(client):
- assert '400' in client.put(f'/v2/portfolios/{test_id}').status
-
-
-def test_update_portfolio_non_existing(client, mocker):
- mocker.patch.object(DB, 'fetch_one', return_value=None)
- assert '404' in client.put(f'/v2/portfolios/{test_id}', json={
- 'portfolio': {
- 'name': 'test',
- 'targets': {
- 'enabledMetrics': ['test'],
- 'repeatsPerScenario': 2
- }
- }
- }).status
-
-
-def test_update_portfolio_not_authorized(client, mocker):
- mocker.patch.object(DB,
- 'fetch_one',
- return_value={
- '_id': test_id,
- 'projectId': test_id,
- 'authorizations': [{
- 'projectId': test_id,
- 'authorizationLevel': 'VIEW'
- }]
- })
- mocker.patch.object(DB, 'update', return_value={})
- assert '403' in client.put(f'/v2/portfolios/{test_id}', json={
- 'portfolio': {
- 'name': 'test',
- 'targets': {
- 'enabledMetrics': ['test'],
- 'repeatsPerScenario': 2
- }
- }
- }).status
-
-
-def test_update_portfolio(client, mocker):
- mocker.patch.object(DB,
- 'fetch_one',
- return_value={
- '_id': test_id,
- 'projectId': test_id,
- 'authorizations': [{
- 'projectId': test_id,
- 'authorizationLevel': 'OWN'
- }],
- 'targets': {
- 'enabledMetrics': [],
- 'repeatsPerScenario': 1
- }
- })
- mocker.patch.object(DB, 'update', return_value={})
-
- res = client.put(f'/v2/portfolios/{test_id}', json={'portfolio': {
- 'name': 'test',
- 'targets': {
- 'enabledMetrics': ['test'],
- 'repeatsPerScenario': 2
- }
- }})
- assert '200' in res.status
-
-
-def test_delete_project_non_existing(client, mocker):
- mocker.patch.object(DB, 'fetch_one', return_value=None)
- assert '404' in client.delete(f'/v2/portfolios/{test_id}').status
-
-
-def test_delete_project_different_user(client, mocker):
- mocker.patch.object(DB,
- 'fetch_one',
- return_value={
- '_id': test_id,
- 'projectId': test_id,
- 'googleId': 'other_test',
- 'authorizations': [{
- 'projectId': test_id,
- 'authorizationLevel': 'VIEW'
- }]
- })
- mocker.patch.object(DB, 'delete_one', return_value=None)
- assert '403' in client.delete(f'/v2/portfolios/{test_id}').status
-
-
-def test_delete_project(client, mocker):
- mocker.patch.object(DB,
- 'fetch_one',
- return_value={
- '_id': test_id,
- 'projectId': test_id,
- 'googleId': 'test',
- 'portfolioIds': [test_id],
- 'authorizations': [{
- 'projectId': test_id,
- 'authorizationLevel': 'OWN'
- }]
- })
- mocker.patch.object(DB, 'delete_one', return_value={})
- mocker.patch.object(DB, 'update', return_value=None)
- res = client.delete(f'/v2/portfolios/{test_id}')
- assert '200' in res.status
diff --git a/api/opendc/api/v2/prefabs/__init__.py b/api/opendc/api/v2/prefabs/__init__.py
deleted file mode 100644
index e69de29b..00000000
--- a/api/opendc/api/v2/prefabs/__init__.py
+++ /dev/null
diff --git a/api/opendc/api/v2/prefabs/authorizations/__init__.py b/api/opendc/api/v2/prefabs/authorizations/__init__.py
deleted file mode 100644
index e69de29b..00000000
--- a/api/opendc/api/v2/prefabs/authorizations/__init__.py
+++ /dev/null
diff --git a/api/opendc/api/v2/prefabs/authorizations/endpoint.py b/api/opendc/api/v2/prefabs/authorizations/endpoint.py
deleted file mode 100644
index 0d9ad5cd..00000000
--- a/api/opendc/api/v2/prefabs/authorizations/endpoint.py
+++ /dev/null
@@ -1,22 +0,0 @@
-from opendc.models.prefab import Prefab
-from opendc.util.database import DB
-from opendc.models.user import User
-from opendc.util.rest import Response
-
-
-def GET(request):
- """Return all prefabs the user is authorized to access"""
-
- user = User.from_google_id(request.google_id)
-
- user.check_exists()
-
- own_prefabs = DB.fetch_all({'authorId': user.get_id()}, Prefab.collection_name)
- public_prefabs = DB.fetch_all({'visibility': 'public'}, Prefab.collection_name)
-
- authorizations = {"authorizations": []}
-
- authorizations["authorizations"].append(own_prefabs)
- authorizations["authorizations"].append(public_prefabs)
-
- return Response(200, 'Successfully fetched authorizations.', authorizations)
diff --git a/api/opendc/api/v2/prefabs/authorizations/test_endpoint.py b/api/opendc/api/v2/prefabs/authorizations/test_endpoint.py
deleted file mode 100644
index 6d36d428..00000000
--- a/api/opendc/api/v2/prefabs/authorizations/test_endpoint.py
+++ /dev/null
@@ -1,71 +0,0 @@
-from opendc.util.database import DB
-from unittest.mock import Mock
-
-test_id = 24 * '1'
-
-
-def test_get_authorizations(client, mocker):
- DB.fetch_all = Mock()
- mocker.patch.object(DB, 'fetch_one', return_value={'_id': test_id})
- DB.fetch_all.side_effect = [
- [{
- '_id': test_id,
- 'datetimeCreated': '000',
- 'datetimeLastEdited': '000',
- 'authorId': test_id,
- 'visibility' : 'private'
- },
- {
- '_id': '2' * 24,
- 'datetimeCreated': '000',
- 'datetimeLastEdited': '000',
- 'authorId': test_id,
- 'visibility' : 'private'
- },
- {
- '_id': '3' * 24,
- 'datetimeCreated': '000',
- 'datetimeLastEdited': '000',
- 'authorId': test_id,
- 'visibility' : 'public'
- },
- {
- '_id': '4' * 24,
- 'datetimeCreated': '000',
- 'datetimeLastEdited': '000',
- 'authorId': test_id,
- 'visibility' : 'public'
- }],
- [{
- '_id': '5' * 24,
- 'datetimeCreated': '000',
- 'datetimeLastEdited': '000',
- 'authorId': '2' * 24,
- 'visibility' : 'public'
- },
- {
- '_id': '6' * 24,
- 'datetimeCreated': '000',
- 'datetimeLastEdited': '000',
- 'authorId': '2' * 24,
- 'visibility' : 'public'
- },
- {
- '_id': '7' * 24,
- 'datetimeCreated': '000',
- 'datetimeLastEdited': '000',
- 'authorId': '2' * 24,
- 'visibility' : 'public'
- },
- {
- '_id': '8' * 24,
- 'datetimeCreated': '000',
- 'datetimeLastEdited': '000',
- 'authorId': '2' * 24,
- 'visibility' : 'public'
- }]
- ]
- mocker.patch.object(DB, 'fetch_one', return_value={'_id': test_id})
- res = client.get('/v2/prefabs/authorizations')
- assert '200' in res.status
-
diff --git a/api/opendc/api/v2/prefabs/endpoint.py b/api/opendc/api/v2/prefabs/endpoint.py
deleted file mode 100644
index 723a2f0d..00000000
--- a/api/opendc/api/v2/prefabs/endpoint.py
+++ /dev/null
@@ -1,23 +0,0 @@
-from datetime import datetime
-
-from opendc.models.prefab import Prefab
-from opendc.models.user import User
-from opendc.util.database import Database
-from opendc.util.rest import Response
-
-
-def POST(request):
- """Create a new prefab, and return that new prefab."""
-
- request.check_required_parameters(body={'prefab': {'name': 'string'}})
-
- prefab = Prefab(request.params_body['prefab'])
- prefab.set_property('datetimeCreated', Database.datetime_to_string(datetime.now()))
- prefab.set_property('datetimeLastEdited', Database.datetime_to_string(datetime.now()))
-
- user = User.from_google_id(request.google_id)
- prefab.set_property('authorId', user.get_id())
-
- prefab.insert()
-
- return Response(200, 'Successfully created prefab.', prefab.obj)
diff --git a/api/opendc/api/v2/prefabs/prefabId/__init__.py b/api/opendc/api/v2/prefabs/prefabId/__init__.py
deleted file mode 100644
index e69de29b..00000000
--- a/api/opendc/api/v2/prefabs/prefabId/__init__.py
+++ /dev/null
diff --git a/api/opendc/api/v2/prefabs/prefabId/endpoint.py b/api/opendc/api/v2/prefabs/prefabId/endpoint.py
deleted file mode 100644
index 7b81f546..00000000
--- a/api/opendc/api/v2/prefabs/prefabId/endpoint.py
+++ /dev/null
@@ -1,50 +0,0 @@
-from datetime import datetime
-
-from opendc.models.prefab import Prefab
-from opendc.util.database import Database
-from opendc.util.rest import Response
-
-
-def GET(request):
- """Get this Prefab."""
-
- request.check_required_parameters(path={'prefabId': 'string'})
-
- prefab = Prefab.from_id(request.params_path['prefabId'])
- prefab.check_exists()
- prefab.check_user_access(request.google_id)
-
- return Response(200, 'Successfully retrieved prefab', prefab.obj)
-
-
-def PUT(request):
- """Update a prefab's name and/or contents."""
-
- request.check_required_parameters(body={'prefab': {'name': 'name'}}, path={'prefabId': 'string'})
-
- prefab = Prefab.from_id(request.params_path['prefabId'])
-
- prefab.check_exists()
- prefab.check_user_access(request.google_id)
-
- prefab.set_property('name', request.params_body['prefab']['name'])
- prefab.set_property('rack', request.params_body['prefab']['rack'])
- prefab.set_property('datetime_last_edited', Database.datetime_to_string(datetime.now()))
- prefab.update()
-
- return Response(200, 'Successfully updated prefab.', prefab.obj)
-
-
-def DELETE(request):
- """Delete this Prefab."""
-
- request.check_required_parameters(path={'prefabId': 'string'})
-
- prefab = Prefab.from_id(request.params_path['prefabId'])
-
- prefab.check_exists()
- prefab.check_user_access(request.google_id)
-
- old_object = prefab.delete()
-
- return Response(200, 'Successfully deleted prefab.', old_object)
diff --git a/api/opendc/api/v2/prefabs/prefabId/test_endpoint.py b/api/opendc/api/v2/prefabs/prefabId/test_endpoint.py
deleted file mode 100644
index 2daeb6bf..00000000
--- a/api/opendc/api/v2/prefabs/prefabId/test_endpoint.py
+++ /dev/null
@@ -1,145 +0,0 @@
-from opendc.util.database import DB
-from unittest.mock import Mock
-
-test_id = 24 * '1'
-test_id_2 = 24 * '2'
-
-
-def test_get_prefab_non_existing(client, mocker):
- mocker.patch.object(DB, 'fetch_one', return_value=None)
- assert '404' in client.get(f'/v2/prefabs/{test_id}').status
-
-
-def test_get_private_prefab_not_authorized(client, mocker):
- DB.fetch_one = Mock()
- DB.fetch_one.side_effect = [{
- '_id': test_id,
- 'name': 'test prefab',
- 'authorId': test_id_2,
- 'visibility': 'private',
- 'rack': {}
- },
- {
- '_id': test_id
- }
- ]
- res = client.get(f'/v2/prefabs/{test_id}')
- assert '403' in res.status
-
-
-def test_get_private_prefab(client, mocker):
- DB.fetch_one = Mock()
- DB.fetch_one.side_effect = [{
- '_id': test_id,
- 'name': 'test prefab',
- 'authorId': test_id,
- 'visibility': 'private',
- 'rack': {}
- },
- {
- '_id': test_id
- }
- ]
- res = client.get(f'/v2/prefabs/{test_id}')
- assert '200' in res.status
-
-
-def test_get_public_prefab(client, mocker):
- DB.fetch_one = Mock()
- DB.fetch_one.side_effect = [{
- '_id': test_id,
- 'name': 'test prefab',
- 'authorId': test_id_2,
- 'visibility': 'public',
- 'rack': {}
- },
- {
- '_id': test_id
- }
- ]
- res = client.get(f'/v2/prefabs/{test_id}')
- assert '200' in res.status
-
-
-def test_update_prefab_missing_parameter(client):
- assert '400' in client.put(f'/v2/prefabs/{test_id}').status
-
-
-def test_update_prefab_non_existing(client, mocker):
- mocker.patch.object(DB, 'fetch_one', return_value=None)
- assert '404' in client.put(f'/v2/prefabs/{test_id}', json={'prefab': {'name': 'S'}}).status
-
-
-def test_update_prefab_not_authorized(client, mocker):
- DB.fetch_one = Mock()
- DB.fetch_one.side_effect = [{
- '_id': test_id,
- 'name': 'test prefab',
- 'authorId': test_id_2,
- 'visibility': 'private',
- 'rack': {}
- },
- {
- '_id': test_id
- }
- ]
- mocker.patch.object(DB, 'update', return_value={})
- assert '403' in client.put(f'/v2/prefabs/{test_id}', json={'prefab': {'name': 'test prefab', 'rack': {}}}).status
-
-
-def test_update_prefab(client, mocker):
- DB.fetch_one = Mock()
- DB.fetch_one.side_effect = [{
- '_id': test_id,
- 'name': 'test prefab',
- 'authorId': test_id,
- 'visibility': 'private',
- 'rack': {}
- },
- {
- '_id': test_id
- }
- ]
- mocker.patch.object(DB, 'update', return_value={})
- res = client.put(f'/v2/prefabs/{test_id}', json={'prefab': {'name': 'test prefab', 'rack': {}}})
- assert '200' in res.status
-
-
-def test_delete_prefab_non_existing(client, mocker):
- mocker.patch.object(DB, 'fetch_one', return_value=None)
- assert '404' in client.delete(f'/v2/prefabs/{test_id}').status
-
-
-def test_delete_prefab_different_user(client, mocker):
- DB.fetch_one = Mock()
- DB.fetch_one.side_effect = [{
- '_id': test_id,
- 'name': 'test prefab',
- 'authorId': test_id_2,
- 'visibility': 'private',
- 'rack': {}
- },
- {
- '_id': test_id
- }
- ]
- mocker.patch.object(DB, 'delete_one', return_value=None)
- assert '403' in client.delete(f'/v2/prefabs/{test_id}').status
-
-
-def test_delete_prefab(client, mocker):
- DB.fetch_one = Mock()
- DB.fetch_one.side_effect = [{
- '_id': test_id,
- 'name': 'test prefab',
- 'authorId': test_id,
- 'visibility': 'private',
- 'rack': {}
- },
- {
- '_id': test_id
- }
- ]
- mocker.patch.object(DB, 'delete_one', return_value={'prefab': {'name': 'name'}})
- res = client.delete(f'/v2/prefabs/{test_id}')
- assert '200' in res.status
diff --git a/api/opendc/api/v2/prefabs/test_endpoint.py b/api/opendc/api/v2/prefabs/test_endpoint.py
deleted file mode 100644
index 39a78c21..00000000
--- a/api/opendc/api/v2/prefabs/test_endpoint.py
+++ /dev/null
@@ -1,24 +0,0 @@
-from opendc.util.database import DB
-
-test_id = 24 * '1'
-
-
-def test_add_prefab_missing_parameter(client):
- assert '400' in client.post('/v2/prefabs').status
-
-
-def test_add_prefab(client, mocker):
- mocker.patch.object(DB, 'fetch_one', return_value={'_id': test_id, 'authorizations': []})
- mocker.patch.object(DB,
- 'insert',
- return_value={
- '_id': test_id,
- 'datetimeCreated': '000',
- 'datetimeLastEdited': '000',
- 'authorId': test_id
- })
- res = client.post('/v2/prefabs', json={'prefab': {'name': 'test prefab'}})
- assert 'datetimeCreated' in res.json['content']
- assert 'datetimeLastEdited' in res.json['content']
- assert 'authorId' in res.json['content']
- assert '200' in res.status
diff --git a/api/opendc/api/v2/projects/__init__.py b/api/opendc/api/v2/projects/__init__.py
deleted file mode 100644
index e69de29b..00000000
--- a/api/opendc/api/v2/projects/__init__.py
+++ /dev/null
diff --git a/api/opendc/api/v2/projects/endpoint.py b/api/opendc/api/v2/projects/endpoint.py
deleted file mode 100644
index bf031382..00000000
--- a/api/opendc/api/v2/projects/endpoint.py
+++ /dev/null
@@ -1,32 +0,0 @@
-from datetime import datetime
-
-from opendc.models.project import Project
-from opendc.models.topology import Topology
-from opendc.models.user import User
-from opendc.util.database import Database
-from opendc.util.rest import Response
-
-
-def POST(request):
- """Create a new project, and return that new project."""
-
- request.check_required_parameters(body={'project': {'name': 'string'}})
-
- topology = Topology({'name': 'Default topology', 'rooms': []})
- topology.insert()
-
- project = Project(request.params_body['project'])
- project.set_property('datetimeCreated', Database.datetime_to_string(datetime.now()))
- project.set_property('datetimeLastEdited', Database.datetime_to_string(datetime.now()))
- project.set_property('topologyIds', [topology.get_id()])
- project.set_property('portfolioIds', [])
- project.insert()
-
- topology.set_property('projectId', project.get_id())
- topology.update()
-
- user = User.from_google_id(request.google_id)
- user.obj['authorizations'].append({'projectId': project.get_id(), 'authorizationLevel': 'OWN'})
- user.update()
-
- return Response(200, 'Successfully created project.', project.obj)
diff --git a/api/opendc/api/v2/projects/projectId/__init__.py b/api/opendc/api/v2/projects/projectId/__init__.py
deleted file mode 100644
index e69de29b..00000000
--- a/api/opendc/api/v2/projects/projectId/__init__.py
+++ /dev/null
diff --git a/api/opendc/api/v2/projects/projectId/authorizations/__init__.py b/api/opendc/api/v2/projects/projectId/authorizations/__init__.py
deleted file mode 100644
index e69de29b..00000000
--- a/api/opendc/api/v2/projects/projectId/authorizations/__init__.py
+++ /dev/null
diff --git a/api/opendc/api/v2/projects/projectId/authorizations/endpoint.py b/api/opendc/api/v2/projects/projectId/authorizations/endpoint.py
deleted file mode 100644
index 9f6a60ec..00000000
--- a/api/opendc/api/v2/projects/projectId/authorizations/endpoint.py
+++ /dev/null
@@ -1,17 +0,0 @@
-from opendc.models.project import Project
-from opendc.util.rest import Response
-
-
-def GET(request):
- """Find all authorizations for a Project."""
-
- request.check_required_parameters(path={'projectId': 'string'})
-
- project = Project.from_id(request.params_path['projectId'])
-
- project.check_exists()
- project.check_user_access(request.google_id, False)
-
- authorizations = project.get_all_authorizations()
-
- return Response(200, 'Successfully retrieved project authorizations', authorizations)
diff --git a/api/opendc/api/v2/projects/projectId/authorizations/test_endpoint.py b/api/opendc/api/v2/projects/projectId/authorizations/test_endpoint.py
deleted file mode 100644
index bebd6cff..00000000
--- a/api/opendc/api/v2/projects/projectId/authorizations/test_endpoint.py
+++ /dev/null
@@ -1,43 +0,0 @@
-from opendc.util.database import DB
-
-test_id = 24 * '1'
-test_id_2 = 24 * '2'
-
-
-def test_get_authorizations_non_existing(client, mocker):
- mocker.patch.object(DB, 'fetch_one', return_value=None)
- mocker.patch.object(DB, 'fetch_all', return_value=None)
- assert '404' in client.get(f'/v2/projects/{test_id}/authorizations').status
-
-
-def test_get_authorizations_not_authorized(client, mocker):
- mocker.patch.object(DB,
- 'fetch_one',
- return_value={
- '_id': test_id,
- 'name': 'test trace',
- 'authorizations': [{
- 'projectId': test_id_2,
- 'authorizationLevel': 'OWN'
- }]
- })
- mocker.patch.object(DB, 'fetch_all', return_value=[])
- res = client.get(f'/v2/projects/{test_id}/authorizations')
- assert '403' in res.status
-
-
-def test_get_authorizations(client, mocker):
- mocker.patch.object(DB,
- 'fetch_one',
- return_value={
- '_id': test_id,
- 'name': 'test trace',
- 'authorizations': [{
- 'projectId': test_id,
- 'authorizationLevel': 'OWN'
- }]
- })
- mocker.patch.object(DB, 'fetch_all', return_value=[])
- res = client.get(f'/v2/projects/{test_id}/authorizations')
- assert len(res.json['content']) == 0
- assert '200' in res.status
diff --git a/api/opendc/api/v2/projects/projectId/endpoint.py b/api/opendc/api/v2/projects/projectId/endpoint.py
deleted file mode 100644
index caac37ca..00000000
--- a/api/opendc/api/v2/projects/projectId/endpoint.py
+++ /dev/null
@@ -1,66 +0,0 @@
-from datetime import datetime
-
-from opendc.models.portfolio import Portfolio
-from opendc.models.project import Project
-from opendc.models.topology import Topology
-from opendc.models.user import User
-from opendc.util.database import Database
-from opendc.util.rest import Response
-
-
-def GET(request):
- """Get this Project."""
-
- request.check_required_parameters(path={'projectId': 'string'})
-
- project = Project.from_id(request.params_path['projectId'])
-
- project.check_exists()
- project.check_user_access(request.google_id, False)
-
- return Response(200, 'Successfully retrieved project', project.obj)
-
-
-def PUT(request):
- """Update a project's name."""
-
- request.check_required_parameters(body={'project': {'name': 'name'}}, path={'projectId': 'string'})
-
- project = Project.from_id(request.params_path['projectId'])
-
- project.check_exists()
- project.check_user_access(request.google_id, True)
-
- project.set_property('name', request.params_body['project']['name'])
- project.set_property('datetime_last_edited', Database.datetime_to_string(datetime.now()))
- project.update()
-
- return Response(200, 'Successfully updated project.', project.obj)
-
-
-def DELETE(request):
- """Delete this Project."""
-
- request.check_required_parameters(path={'projectId': 'string'})
-
- project = Project.from_id(request.params_path['projectId'])
-
- project.check_exists()
- project.check_user_access(request.google_id, True)
-
- for topology_id in project.obj['topologyIds']:
- topology = Topology.from_id(topology_id)
- topology.delete()
-
- for portfolio_id in project.obj['portfolioIds']:
- portfolio = Portfolio.from_id(portfolio_id)
- portfolio.delete()
-
- user = User.from_google_id(request.google_id)
- user.obj['authorizations'] = list(
- filter(lambda x: x['projectId'] != project.get_id(), user.obj['authorizations']))
- user.update()
-
- old_object = project.delete()
-
- return Response(200, 'Successfully deleted project.', old_object)
diff --git a/api/opendc/api/v2/projects/projectId/portfolios/__init__.py b/api/opendc/api/v2/projects/projectId/portfolios/__init__.py
deleted file mode 100644
index e69de29b..00000000
--- a/api/opendc/api/v2/projects/projectId/portfolios/__init__.py
+++ /dev/null
diff --git a/api/opendc/api/v2/projects/projectId/portfolios/endpoint.py b/api/opendc/api/v2/projects/projectId/portfolios/endpoint.py
deleted file mode 100644
index 2cdb1194..00000000
--- a/api/opendc/api/v2/projects/projectId/portfolios/endpoint.py
+++ /dev/null
@@ -1,35 +0,0 @@
-from opendc.models.portfolio import Portfolio
-from opendc.models.project import Project
-from opendc.util.rest import Response
-
-
-def POST(request):
- """Add a new Portfolio for this Project."""
-
- request.check_required_parameters(path={'projectId': 'string'},
- body={
- 'portfolio': {
- 'name': 'string',
- 'targets': {
- 'enabledMetrics': 'list',
- 'repeatsPerScenario': 'int',
- },
- }
- })
-
- project = Project.from_id(request.params_path['projectId'])
-
- project.check_exists()
- project.check_user_access(request.google_id, True)
-
- portfolio = Portfolio(request.params_body['portfolio'])
-
- portfolio.set_property('projectId', project.get_id())
- portfolio.set_property('scenarioIds', [])
-
- portfolio.insert()
-
- project.obj['portfolioIds'].append(portfolio.get_id())
- project.update()
-
- return Response(200, 'Successfully added Portfolio.', portfolio.obj)
diff --git a/api/opendc/api/v2/projects/projectId/portfolios/test_endpoint.py b/api/opendc/api/v2/projects/projectId/portfolios/test_endpoint.py
deleted file mode 100644
index 04c699b5..00000000
--- a/api/opendc/api/v2/projects/projectId/portfolios/test_endpoint.py
+++ /dev/null
@@ -1,85 +0,0 @@
-from opendc.util.database import DB
-
-test_id = 24 * '1'
-
-
-def test_add_portfolio_missing_parameter(client):
- assert '400' in client.post(f'/v2/projects/{test_id}/portfolios').status
-
-
-def test_add_portfolio_non_existing_project(client, mocker):
- mocker.patch.object(DB, 'fetch_one', return_value=None)
- assert '404' in client.post(f'/v2/projects/{test_id}/portfolios',
- json={
- 'portfolio': {
- 'name': 'test',
- 'targets': {
- 'enabledMetrics': ['test'],
- 'repeatsPerScenario': 2
- }
- }
- }).status
-
-
-def test_add_portfolio_not_authorized(client, mocker):
- mocker.patch.object(DB,
- 'fetch_one',
- return_value={
- '_id': test_id,
- 'projectId': test_id,
- 'authorizations': [{
- 'projectId': test_id,
- 'authorizationLevel': 'VIEW'
- }]
- })
- assert '403' in client.post(f'/v2/projects/{test_id}/portfolios',
- json={
- 'portfolio': {
- 'name': 'test',
- 'targets': {
- 'enabledMetrics': ['test'],
- 'repeatsPerScenario': 2
- }
- }
- }).status
-
-
-def test_add_portfolio(client, mocker):
- mocker.patch.object(DB,
- 'fetch_one',
- return_value={
- '_id': test_id,
- 'projectId': test_id,
- 'portfolioIds': [test_id],
- 'authorizations': [{
- 'projectId': test_id,
- 'authorizationLevel': 'EDIT'
- }]
- })
- mocker.patch.object(DB,
- 'insert',
- return_value={
- '_id': test_id,
- 'name': 'test',
- 'targets': {
- 'enabledMetrics': ['test'],
- 'repeatsPerScenario': 2
- },
- 'projectId': test_id,
- 'scenarioIds': [],
- })
- mocker.patch.object(DB, 'update', return_value=None)
- res = client.post(
- f'/v2/projects/{test_id}/portfolios',
- json={
- 'portfolio': {
- 'name': 'test',
- 'targets': {
- 'enabledMetrics': ['test'],
- 'repeatsPerScenario': 2
- }
- }
- })
- assert 'projectId' in res.json['content']
- assert 'scenarioIds' in res.json['content']
- assert '200' in res.status
diff --git a/api/opendc/api/v2/projects/projectId/test_endpoint.py b/api/opendc/api/v2/projects/projectId/test_endpoint.py
deleted file mode 100644
index f9ffaf37..00000000
--- a/api/opendc/api/v2/projects/projectId/test_endpoint.py
+++ /dev/null
@@ -1,122 +0,0 @@
-from opendc.util.database import DB
-
-test_id = 24 * '1'
-test_id_2 = 24 * '2'
-
-
-def test_get_project_non_existing(client, mocker):
- mocker.patch.object(DB, 'fetch_one', return_value=None)
- assert '404' in client.get(f'/v2/projects/{test_id}').status
-
-
-def test_get_project_no_authorizations(client, mocker):
- mocker.patch.object(DB, 'fetch_one', return_value={'authorizations': []})
- res = client.get(f'/v2/projects/{test_id}')
- assert '403' in res.status
-
-
-def test_get_project_not_authorized(client, mocker):
- mocker.patch.object(DB,
- 'fetch_one',
- return_value={
- '_id': test_id,
- 'authorizations': [{
- 'projectId': test_id_2,
- 'authorizationLevel': 'OWN'
- }]
- })
- res = client.get(f'/v2/projects/{test_id}')
- assert '403' in res.status
-
-
-def test_get_project(client, mocker):
- mocker.patch.object(DB,
- 'fetch_one',
- return_value={
- '_id': test_id,
- 'authorizations': [{
- 'projectId': test_id,
- 'authorizationLevel': 'EDIT'
- }]
- })
- res = client.get(f'/v2/projects/{test_id}')
- assert '200' in res.status
-
-
-def test_update_project_missing_parameter(client):
- assert '400' in client.put(f'/v2/projects/{test_id}').status
-
-
-def test_update_project_non_existing(client, mocker):
- mocker.patch.object(DB, 'fetch_one', return_value=None)
- assert '404' in client.put(f'/v2/projects/{test_id}', json={'project': {'name': 'S'}}).status
-
-
-def test_update_project_not_authorized(client, mocker):
- mocker.patch.object(DB,
- 'fetch_one',
- return_value={
- '_id': test_id,
- 'authorizations': [{
- 'projectId': test_id,
- 'authorizationLevel': 'VIEW'
- }]
- })
- mocker.patch.object(DB, 'update', return_value={})
- assert '403' in client.put(f'/v2/projects/{test_id}', json={'project': {'name': 'S'}}).status
-
-
-def test_update_project(client, mocker):
- mocker.patch.object(DB,
- 'fetch_one',
- return_value={
- '_id': test_id,
- 'authorizations': [{
- 'projectId': test_id,
- 'authorizationLevel': 'OWN'
- }]
- })
- mocker.patch.object(DB, 'update', return_value={})
-
- res = client.put(f'/v2/projects/{test_id}', json={'project': {'name': 'S'}})
- assert '200' in res.status
-
-
-def test_delete_project_non_existing(client, mocker):
- mocker.patch.object(DB, 'fetch_one', return_value=None)
- assert '404' in client.delete(f'/v2/projects/{test_id}').status
-
-
-def test_delete_project_different_user(client, mocker):
- mocker.patch.object(DB,
- 'fetch_one',
- return_value={
- '_id': test_id,
- 'googleId': 'other_test',
- 'authorizations': [{
- 'projectId': test_id,
- 'authorizationLevel': 'VIEW'
- }],
- 'topologyIds': []
- })
- mocker.patch.object(DB, 'delete_one', return_value=None)
- assert '403' in client.delete(f'/v2/projects/{test_id}').status
-
-
-def test_delete_project(client, mocker):
- mocker.patch.object(DB,
- 'fetch_one',
- return_value={
- '_id': test_id,
- 'googleId': 'test',
- 'authorizations': [{
- 'projectId': test_id,
- 'authorizationLevel': 'OWN'
- }],
- 'topologyIds': [],
- 'portfolioIds': [],
- })
- mocker.patch.object(DB, 'update', return_value=None)
- mocker.patch.object(DB, 'delete_one', return_value={'googleId': 'test'})
- res = client.delete(f'/v2/projects/{test_id}')
- assert '200' in res.status
diff --git a/api/opendc/api/v2/projects/projectId/topologies/__init__.py b/api/opendc/api/v2/projects/projectId/topologies/__init__.py
deleted file mode 100644
index e69de29b..00000000
--- a/api/opendc/api/v2/projects/projectId/topologies/__init__.py
+++ /dev/null
diff --git a/api/opendc/api/v2/projects/projectId/topologies/endpoint.py b/api/opendc/api/v2/projects/projectId/topologies/endpoint.py
deleted file mode 100644
index 44a0d575..00000000
--- a/api/opendc/api/v2/projects/projectId/topologies/endpoint.py
+++ /dev/null
@@ -1,31 +0,0 @@
-from datetime import datetime
-
-from opendc.models.project import Project
-from opendc.models.topology import Topology
-from opendc.util.rest import Response
-from opendc.util.database import Database
-
-
-def POST(request):
- """Add a new Topology to the specified project and return it"""
-
- request.check_required_parameters(path={'projectId': 'string'}, body={'topology': {'name': 'string'}})
-
- project = Project.from_id(request.params_path['projectId'])
-
- project.check_exists()
- project.check_user_access(request.google_id, True)
-
- topology = Topology({
- 'projectId': project.get_id(),
- 'name': request.params_body['topology']['name'],
- 'rooms': request.params_body['topology']['rooms'],
- })
-
- topology.insert()
-
- project.obj['topologyIds'].append(topology.get_id())
- project.set_property('datetimeLastEdited', Database.datetime_to_string(datetime.now()))
- project.update()
-
- return Response(200, 'Successfully inserted topology.', topology.obj)
diff --git a/api/opendc/api/v2/projects/projectId/topologies/test_endpoint.py b/api/opendc/api/v2/projects/projectId/topologies/test_endpoint.py
deleted file mode 100644
index 71e88f00..00000000
--- a/api/opendc/api/v2/projects/projectId/topologies/test_endpoint.py
+++ /dev/null
@@ -1,52 +0,0 @@
-from opendc.util.database import DB
-
-test_id = 24 * '1'
-
-
-def test_add_topology_missing_parameter(client):
- assert '400' in client.post(f'/v2/projects/{test_id}/topologies').status
-
-
-def test_add_topology(client, mocker):
- mocker.patch.object(DB,
- 'fetch_one',
- return_value={
- '_id': test_id,
- 'authorizations': [{
- 'projectId': test_id,
- 'authorizationLevel': 'OWN'
- }],
- 'topologyIds': []
- })
- mocker.patch.object(DB,
- 'insert',
- return_value={
- '_id': test_id,
- 'datetimeCreated': '000',
- 'datetimeLastEdited': '000',
- 'topologyIds': []
- })
- mocker.patch.object(DB, 'update', return_value={})
- res = client.post(f'/v2/projects/{test_id}/topologies', json={'topology': {'name': 'test project', 'rooms': []}})
- assert 'rooms' in res.json['content']
- assert '200' in res.status
-
-
-def test_add_topology_not_authorized(client, mocker):
- mocker.patch.object(DB,
- 'fetch_one',
- return_value={
- '_id': test_id,
- 'projectId': test_id,
- 'authorizations': [{
- 'projectId': test_id,
- 'authorizationLevel': 'VIEW'
- }]
- })
- assert '403' in client.post(f'/v2/projects/{test_id}/topologies',
- json={
- 'topology': {
- 'name': 'test_topology',
- 'rooms': {}
- }
- }).status
diff --git a/api/opendc/api/v2/projects/test_endpoint.py b/api/opendc/api/v2/projects/test_endpoint.py
deleted file mode 100644
index 9444b1e4..00000000
--- a/api/opendc/api/v2/projects/test_endpoint.py
+++ /dev/null
@@ -1,25 +0,0 @@
-from opendc.util.database import DB
-
-test_id = 24 * '1'
-
-
-def test_add_project_missing_parameter(client):
- assert '400' in client.post('/v2/projects').status
-
-
-def test_add_project(client, mocker):
- mocker.patch.object(DB, 'fetch_one', return_value={'_id': test_id, 'authorizations': []})
- mocker.patch.object(DB,
- 'insert',
- return_value={
- '_id': test_id,
- 'datetimeCreated': '000',
- 'datetimeLastEdited': '000',
- 'topologyIds': []
- })
- mocker.patch.object(DB, 'update', return_value={})
- res = client.post('/v2/projects', json={'project': {'name': 'test project'}})
- assert 'datetimeCreated' in res.json['content']
- assert 'datetimeLastEdited' in res.json['content']
- assert 'topologyIds' in res.json['content']
- assert '200' in res.status
diff --git a/api/opendc/api/v2/scenarios/__init__.py b/api/opendc/api/v2/scenarios/__init__.py
deleted file mode 100644
index e69de29b..00000000
--- a/api/opendc/api/v2/scenarios/__init__.py
+++ /dev/null
diff --git a/api/opendc/api/v2/scenarios/scenarioId/__init__.py b/api/opendc/api/v2/scenarios/scenarioId/__init__.py
deleted file mode 100644
index e69de29b..00000000
--- a/api/opendc/api/v2/scenarios/scenarioId/__init__.py
+++ /dev/null
diff --git a/api/opendc/api/v2/scenarios/scenarioId/endpoint.py b/api/opendc/api/v2/scenarios/scenarioId/endpoint.py
deleted file mode 100644
index 88a74e9c..00000000
--- a/api/opendc/api/v2/scenarios/scenarioId/endpoint.py
+++ /dev/null
@@ -1,59 +0,0 @@
-from opendc.models.scenario import Scenario
-from opendc.models.portfolio import Portfolio
-from opendc.util.rest import Response
-
-
-def GET(request):
- """Get this Scenario."""
-
- request.check_required_parameters(path={'scenarioId': 'string'})
-
- scenario = Scenario.from_id(request.params_path['scenarioId'])
-
- scenario.check_exists()
- scenario.check_user_access(request.google_id, False)
-
- return Response(200, 'Successfully retrieved scenario.', scenario.obj)
-
-
-def PUT(request):
- """Update this Scenarios name."""
-
- request.check_required_parameters(path={'scenarioId': 'string'}, body={'scenario': {
- 'name': 'string',
- }})
-
- scenario = Scenario.from_id(request.params_path['scenarioId'])
-
- scenario.check_exists()
- scenario.check_user_access(request.google_id, True)
-
- scenario.set_property('name',
- request.params_body['scenario']['name'])
-
- scenario.update()
-
- return Response(200, 'Successfully updated scenario.', scenario.obj)
-
-
-def DELETE(request):
- """Delete this Scenario."""
-
- request.check_required_parameters(path={'scenarioId': 'string'})
-
- scenario = Scenario.from_id(request.params_path['scenarioId'])
-
- scenario.check_exists()
- scenario.check_user_access(request.google_id, True)
-
- scenario_id = scenario.get_id()
-
- portfolio = Portfolio.from_id(scenario.obj['portfolioId'])
- portfolio.check_exists()
- if scenario_id in portfolio.obj['scenarioIds']:
- portfolio.obj['scenarioIds'].remove(scenario_id)
- portfolio.update()
-
- old_object = scenario.delete()
-
- return Response(200, 'Successfully deleted scenario.', old_object)
diff --git a/api/opendc/api/v2/scenarios/scenarioId/test_endpoint.py b/api/opendc/api/v2/scenarios/scenarioId/test_endpoint.py
deleted file mode 100644
index cd4bcdf8..00000000
--- a/api/opendc/api/v2/scenarios/scenarioId/test_endpoint.py
+++ /dev/null
@@ -1,149 +0,0 @@
-from opendc.util.database import DB
-
-test_id = 24 * '1'
-test_id_2 = 24 * '2'
-
-
-def test_get_scenario_non_existing(client, mocker):
- mocker.patch.object(DB, 'fetch_one', return_value=None)
- assert '404' in client.get(f'/v2/scenarios/{test_id}').status
-
-
-def test_get_scenario_no_authorizations(client, mocker):
- mocker.patch.object(DB, 'fetch_one', return_value={
- 'portfolioId': '1',
- 'authorizations': []
- })
- res = client.get(f'/v2/scenarios/{test_id}')
- assert '403' in res.status
-
-
-def test_get_scenario_not_authorized(client, mocker):
- mocker.patch.object(DB,
- 'fetch_one',
- return_value={
- 'projectId': test_id,
- 'portfolioId': test_id,
- '_id': test_id,
- 'authorizations': [{
- 'projectId': test_id_2,
- 'authorizationLevel': 'OWN'
- }]
- })
- res = client.get(f'/v2/scenarios/{test_id}')
- assert '403' in res.status
-
-
-def test_get_scenario(client, mocker):
- mocker.patch.object(DB,
- 'fetch_one',
- return_value={
- 'projectId': test_id,
- 'portfolioId': test_id,
- '_id': test_id,
- 'authorizations': [{
- 'projectId': test_id,
- 'authorizationLevel': 'EDIT'
- }]
- })
- res = client.get(f'/v2/scenarios/{test_id}')
- assert '200' in res.status
-
-
-def test_update_scenario_missing_parameter(client):
- assert '400' in client.put(f'/v2/scenarios/{test_id}').status
-
-
-def test_update_scenario_non_existing(client, mocker):
- mocker.patch.object(DB, 'fetch_one', return_value=None)
- assert '404' in client.put(f'/v2/scenarios/{test_id}', json={
- 'scenario': {
- 'name': 'test',
- }
- }).status
-
-
-def test_update_scenario_not_authorized(client, mocker):
- mocker.patch.object(DB,
- 'fetch_one',
- return_value={
- '_id': test_id,
- 'projectId': test_id,
- 'portfolioId': test_id,
- 'authorizations': [{
- 'projectId': test_id,
- 'authorizationLevel': 'VIEW'
- }]
- })
- mocker.patch.object(DB, 'update', return_value={})
- assert '403' in client.put(f'/v2/scenarios/{test_id}', json={
- 'scenario': {
- 'name': 'test',
- }
- }).status
-
-
-def test_update_scenario(client, mocker):
- mocker.patch.object(DB,
- 'fetch_one',
- return_value={
- '_id': test_id,
- 'projectId': test_id,
- 'portfolioId': test_id,
- 'authorizations': [{
- 'projectId': test_id,
- 'authorizationLevel': 'OWN'
- }],
- 'targets': {
- 'enabledMetrics': [],
- 'repeatsPerScenario': 1
- }
- })
- mocker.patch.object(DB, 'update', return_value={})
-
- res = client.put(f'/v2/scenarios/{test_id}', json={'scenario': {
- 'name': 'test',
- }})
- assert '200' in res.status
-
-
-def test_delete_project_non_existing(client, mocker):
- mocker.patch.object(DB, 'fetch_one', return_value=None)
- assert '404' in client.delete(f'/v2/scenarios/{test_id}').status
-
-
-def test_delete_project_different_user(client, mocker):
- mocker.patch.object(DB,
- 'fetch_one',
- return_value={
- '_id': test_id,
- 'projectId': test_id,
- 'portfolioId': test_id,
- 'googleId': 'other_test',
- 'authorizations': [{
- 'projectId': test_id,
- 'authorizationLevel': 'VIEW'
- }]
- })
- mocker.patch.object(DB, 'delete_one', return_value=None)
- assert '403' in client.delete(f'/v2/scenarios/{test_id}').status
-
-
-def test_delete_project(client, mocker):
- mocker.patch.object(DB,
- 'fetch_one',
- return_value={
- '_id': test_id,
- 'projectId': test_id,
- 'portfolioId': test_id,
- 'googleId': 'test',
- 'scenarioIds': [test_id],
- 'authorizations': [{
- 'projectId': test_id,
- 'authorizationLevel': 'OWN'
- }]
- })
- mocker.patch.object(DB, 'delete_one', return_value={})
- mocker.patch.object(DB, 'update', return_value=None)
- res = client.delete(f'/v2/scenarios/{test_id}')
- assert '200' in res.status
diff --git a/api/opendc/api/v2/schedulers/__init__.py b/api/opendc/api/v2/schedulers/__init__.py
deleted file mode 100644
index e69de29b..00000000
--- a/api/opendc/api/v2/schedulers/__init__.py
+++ /dev/null
diff --git a/api/opendc/api/v2/schedulers/endpoint.py b/api/opendc/api/v2/schedulers/endpoint.py
deleted file mode 100644
index f33159bf..00000000
--- a/api/opendc/api/v2/schedulers/endpoint.py
+++ /dev/null
@@ -1,19 +0,0 @@
-from opendc.util.rest import Response
-
-SCHEDULERS = [
- 'mem',
- 'mem-inv',
- 'core-mem',
- 'core-mem-inv',
- 'active-servers',
- 'active-servers-inv',
- 'provisioned-cores',
- 'provisioned-cores-inv',
- 'random'
-]
-
-
-def GET(_):
- """Get all available Schedulers."""
-
- return Response(200, 'Successfully retrieved Schedulers.', [{'name': name} for name in SCHEDULERS])
diff --git a/api/opendc/api/v2/schedulers/test_endpoint.py b/api/opendc/api/v2/schedulers/test_endpoint.py
deleted file mode 100644
index 4950ca4c..00000000
--- a/api/opendc/api/v2/schedulers/test_endpoint.py
+++ /dev/null
@@ -1,2 +0,0 @@
-def test_get_schedulers(client):
- assert '200' in client.get('/v2/schedulers').status
diff --git a/api/opendc/api/v2/topologies/__init__.py b/api/opendc/api/v2/topologies/__init__.py
deleted file mode 100644
index e69de29b..00000000
--- a/api/opendc/api/v2/topologies/__init__.py
+++ /dev/null
diff --git a/api/opendc/api/v2/topologies/topologyId/__init__.py b/api/opendc/api/v2/topologies/topologyId/__init__.py
deleted file mode 100644
index e69de29b..00000000
--- a/api/opendc/api/v2/topologies/topologyId/__init__.py
+++ /dev/null
diff --git a/api/opendc/api/v2/topologies/topologyId/endpoint.py b/api/opendc/api/v2/topologies/topologyId/endpoint.py
deleted file mode 100644
index ea82b2e2..00000000
--- a/api/opendc/api/v2/topologies/topologyId/endpoint.py
+++ /dev/null
@@ -1,58 +0,0 @@
-from datetime import datetime
-
-from opendc.util.database import Database
-from opendc.models.project import Project
-from opendc.models.topology import Topology
-from opendc.util.rest import Response
-
-
-def GET(request):
- """Get this Topology."""
-
- request.check_required_parameters(path={'topologyId': 'string'})
-
- topology = Topology.from_id(request.params_path['topologyId'])
-
- topology.check_exists()
- topology.check_user_access(request.google_id, False)
-
- return Response(200, 'Successfully retrieved topology.', topology.obj)
-
-
-def PUT(request):
- """Update this topology"""
- request.check_required_parameters(path={'topologyId': 'string'}, body={'topology': {'name': 'string', 'rooms': {}}})
- topology = Topology.from_id(request.params_path['topologyId'])
-
- topology.check_exists()
- topology.check_user_access(request.google_id, True)
-
- topology.set_property('name', request.params_body['topology']['name'])
- topology.set_property('rooms', request.params_body['topology']['rooms'])
- topology.set_property('datetimeLastEdited', Database.datetime_to_string(datetime.now()))
-
- topology.update()
-
- return Response(200, 'Successfully updated topology.', topology.obj)
-
-
-def DELETE(request):
- """Delete this topology"""
- request.check_required_parameters(path={'topologyId': 'string'})
-
- topology = Topology.from_id(request.params_path['topologyId'])
-
- topology.check_exists()
- topology.check_user_access(request.google_id, True)
-
- topology_id = topology.get_id()
-
- project = Project.from_id(topology.obj['projectId'])
- project.check_exists()
- if topology_id in project.obj['topologyIds']:
- project.obj['topologyIds'].remove(topology_id)
- project.update()
-
- old_object = topology.delete()
-
- return Response(200, 'Successfully deleted topology.', old_object)
diff --git a/api/opendc/api/v2/topologies/topologyId/test_endpoint.py b/api/opendc/api/v2/topologies/topologyId/test_endpoint.py
deleted file mode 100644
index 4da0bc64..00000000
--- a/api/opendc/api/v2/topologies/topologyId/test_endpoint.py
+++ /dev/null
@@ -1,119 +0,0 @@
-from opendc.util.database import DB
-
-test_id = 24 * '1'
-test_id_2 = 24 * '2'
-
-
-def test_get_topology(client, mocker):
- mocker.patch.object(DB,
- 'fetch_one',
- return_value={
- '_id': test_id,
- 'projectId': test_id,
- 'authorizations': [{
- 'projectId': test_id,
- 'authorizationLevel': 'EDIT'
- }]
- })
- res = client.get(f'/v2/topologies/{test_id}')
- assert '200' in res.status
-
-
-def test_get_topology_non_existing(client, mocker):
- mocker.patch.object(DB, 'fetch_one', return_value=None)
- assert '404' in client.get('/v2/topologies/1').status
-
-
-def test_get_topology_not_authorized(client, mocker):
- mocker.patch.object(DB,
- 'fetch_one',
- return_value={
- '_id': test_id,
- 'projectId': test_id,
- 'authorizations': [{
- 'projectId': test_id_2,
- 'authorizationLevel': 'OWN'
- }]
- })
- res = client.get(f'/v2/topologies/{test_id}')
- assert '403' in res.status
-
-
-def test_get_topology_no_authorizations(client, mocker):
- mocker.patch.object(DB, 'fetch_one', return_value={'projectId': test_id, 'authorizations': []})
- res = client.get(f'/v2/topologies/{test_id}')
- assert '403' in res.status
-
-
-def test_update_topology_missing_parameter(client):
- assert '400' in client.put(f'/v2/topologies/{test_id}').status
-
-
-def test_update_topology_non_existent(client, mocker):
- mocker.patch.object(DB, 'fetch_one', return_value=None)
- assert '404' in client.put(f'/v2/topologies/{test_id}', json={'topology': {'name': 'test_topology', 'rooms': {}}}).status
-
-
-def test_update_topology_not_authorized(client, mocker):
- mocker.patch.object(DB,
- 'fetch_one',
- return_value={
- '_id': test_id,
- 'projectId': test_id,
- 'authorizations': [{
- 'projectId': test_id,
- 'authorizationLevel': 'VIEW'
- }]
- })
- mocker.patch.object(DB, 'update', return_value={})
- assert '403' in client.put(f'/v2/topologies/{test_id}', json={
- 'topology': {
- 'name': 'updated_topology',
- 'rooms': {}
- }
- }).status
-
-
-def test_update_topology(client, mocker):
- mocker.patch.object(DB,
- 'fetch_one',
- return_value={
- '_id': test_id,
- 'projectId': test_id,
- 'authorizations': [{
- 'projectId': test_id,
- 'authorizationLevel': 'OWN'
- }]
- })
- mocker.patch.object(DB, 'update', return_value={})
-
- assert '200' in client.put(f'/v2/topologies/{test_id}', json={
- 'topology': {
- 'name': 'updated_topology',
- 'rooms': {}
- }
- }).status
-
-
-def test_delete_topology(client, mocker):
- mocker.patch.object(DB,
- 'fetch_one',
- return_value={
- '_id': test_id,
- 'projectId': test_id,
- 'googleId': 'test',
- 'topologyIds': [test_id],
- 'authorizations': [{
- 'projectId': test_id,
- 'authorizationLevel': 'OWN'
- }]
- })
- mocker.patch.object(DB, 'delete_one', return_value={})
- mocker.patch.object(DB, 'update', return_value=None)
- res = client.delete(f'/v2/topologies/{test_id}')
- assert '200' in res.status
-
-
-def test_delete_nonexistent_topology(client, mocker):
- mocker.patch.object(DB, 'fetch_one', return_value=None)
- assert '404' in client.delete(f'/v2/topologies/{test_id}').status
diff --git a/api/opendc/api/v2/traces/__init__.py b/api/opendc/api/v2/traces/__init__.py
deleted file mode 100644
index e69de29b..00000000
--- a/api/opendc/api/v2/traces/__init__.py
+++ /dev/null
diff --git a/api/opendc/api/v2/traces/endpoint.py b/api/opendc/api/v2/traces/endpoint.py
deleted file mode 100644
index ee699e02..00000000
--- a/api/opendc/api/v2/traces/endpoint.py
+++ /dev/null
@@ -1,10 +0,0 @@
-from opendc.models.trace import Trace
-from opendc.util.rest import Response
-
-
-def GET(_):
- """Get all available Traces."""
-
- traces = Trace.get_all()
-
- return Response(200, 'Successfully retrieved Traces', traces.obj)
diff --git a/api/opendc/api/v2/traces/test_endpoint.py b/api/opendc/api/v2/traces/test_endpoint.py
deleted file mode 100644
index 36846bd9..00000000
--- a/api/opendc/api/v2/traces/test_endpoint.py
+++ /dev/null
@@ -1,6 +0,0 @@
-from opendc.util.database import DB
-
-
-def test_get_traces(client, mocker):
- mocker.patch.object(DB, 'fetch_all', return_value=[])
- assert '200' in client.get('/v2/traces').status
diff --git a/api/opendc/api/v2/traces/traceId/__init__.py b/api/opendc/api/v2/traces/traceId/__init__.py
deleted file mode 100644
index e69de29b..00000000
--- a/api/opendc/api/v2/traces/traceId/__init__.py
+++ /dev/null
diff --git a/api/opendc/api/v2/traces/traceId/endpoint.py b/api/opendc/api/v2/traces/traceId/endpoint.py
deleted file mode 100644
index 670f88d1..00000000
--- a/api/opendc/api/v2/traces/traceId/endpoint.py
+++ /dev/null
@@ -1,14 +0,0 @@
-from opendc.models.trace import Trace
-from opendc.util.rest import Response
-
-
-def GET(request):
- """Get this Trace."""
-
- request.check_required_parameters(path={'traceId': 'string'})
-
- trace = Trace.from_id(request.params_path['traceId'])
-
- trace.check_exists()
-
- return Response(200, 'Successfully retrieved trace.', trace.obj)
diff --git a/api/opendc/api/v2/traces/traceId/test_endpoint.py b/api/opendc/api/v2/traces/traceId/test_endpoint.py
deleted file mode 100644
index 0c51538b..00000000
--- a/api/opendc/api/v2/traces/traceId/test_endpoint.py
+++ /dev/null
@@ -1,15 +0,0 @@
-from opendc.util.database import DB
-
-test_id = 24 * '1'
-
-
-def test_get_trace_non_existing(client, mocker):
- mocker.patch.object(DB, 'fetch_one', return_value=None)
- assert '404' in client.get(f'/v2/traces/{test_id}').status
-
-
-def test_get_trace(client, mocker):
- mocker.patch.object(DB, 'fetch_one', return_value={'name': 'test trace'})
- res = client.get(f'/v2/traces/{test_id}')
- assert 'name' in res.json['content']
- assert '200' in res.status
diff --git a/api/opendc/api/v2/users/__init__.py b/api/opendc/api/v2/users/__init__.py
deleted file mode 100644
index e69de29b..00000000
--- a/api/opendc/api/v2/users/__init__.py
+++ /dev/null
diff --git a/api/opendc/api/v2/users/endpoint.py b/api/opendc/api/v2/users/endpoint.py
deleted file mode 100644
index 0dcf2463..00000000
--- a/api/opendc/api/v2/users/endpoint.py
+++ /dev/null
@@ -1,30 +0,0 @@
-from opendc.models.user import User
-from opendc.util.rest import Response
-
-
-def GET(request):
- """Search for a User using their email address."""
-
- request.check_required_parameters(query={'email': 'string'})
-
- user = User.from_email(request.params_query['email'])
-
- user.check_exists()
-
- return Response(200, 'Successfully retrieved user.', user.obj)
-
-
-def POST(request):
- """Add a new User."""
-
- request.check_required_parameters(body={'user': {'email': 'string'}})
-
- user = User(request.params_body['user'])
- user.set_property('googleId', request.google_id)
- user.set_property('authorizations', [])
-
- user.check_already_exists()
-
- user.insert()
-
- return Response(200, 'Successfully created user.', user.obj)
diff --git a/api/opendc/api/v2/users/test_endpoint.py b/api/opendc/api/v2/users/test_endpoint.py
deleted file mode 100644
index 13b63b20..00000000
--- a/api/opendc/api/v2/users/test_endpoint.py
+++ /dev/null
@@ -1,34 +0,0 @@
-from opendc.util.database import DB
-
-
-def test_get_user_by_email_missing_parameter(client):
- assert '400' in client.get('/v2/users').status
-
-
-def test_get_user_by_email_non_existing(client, mocker):
- mocker.patch.object(DB, 'fetch_one', return_value=None)
- assert '404' in client.get('/v2/users?email=test@test.com').status
-
-
-def test_get_user_by_email(client, mocker):
- mocker.patch.object(DB, 'fetch_one', return_value={'email': 'test@test.com'})
- res = client.get('/v2/users?email=test@test.com')
- assert 'email' in res.json['content']
- assert '200' in res.status
-
-
-def test_add_user_missing_parameter(client):
- assert '400' in client.post('/v2/users').status
-
-
-def test_add_user_existing(client, mocker):
- mocker.patch.object(DB, 'fetch_one', return_value={'email': 'test@test.com'})
- assert '409' in client.post('/v2/users', json={'user': {'email': 'test@test.com'}}).status
-
-
-def test_add_user(client, mocker):
- mocker.patch.object(DB, 'fetch_one', return_value=None)
- mocker.patch.object(DB, 'insert', return_value={'email': 'test@test.com'})
- res = client.post('/v2/users', json={'user': {'email': 'test@test.com'}})
- assert 'email' in res.json['content']
- assert '200' in res.status
diff --git a/api/opendc/api/v2/users/userId/__init__.py b/api/opendc/api/v2/users/userId/__init__.py
deleted file mode 100644
index e69de29b..00000000
--- a/api/opendc/api/v2/users/userId/__init__.py
+++ /dev/null
diff --git a/api/opendc/api/v2/users/userId/endpoint.py b/api/opendc/api/v2/users/userId/endpoint.py
deleted file mode 100644
index be3462c0..00000000
--- a/api/opendc/api/v2/users/userId/endpoint.py
+++ /dev/null
@@ -1,59 +0,0 @@
-from opendc.models.project import Project
-from opendc.models.user import User
-from opendc.util.rest import Response
-
-
-def GET(request):
- """Get this User."""
-
- request.check_required_parameters(path={'userId': 'string'})
-
- user = User.from_id(request.params_path['userId'])
-
- user.check_exists()
-
- return Response(200, 'Successfully retrieved user.', user.obj)
-
-
-def PUT(request):
- """Update this User's given name and/or family name."""
-
- request.check_required_parameters(body={'user': {
- 'givenName': 'string',
- 'familyName': 'string'
- }},
- path={'userId': 'string'})
-
- user = User.from_id(request.params_path['userId'])
-
- user.check_exists()
- user.check_correct_user(request.google_id)
-
- user.set_property('givenName', request.params_body['user']['givenName'])
- user.set_property('familyName', request.params_body['user']['familyName'])
-
- user.update()
-
- return Response(200, 'Successfully updated user.', user.obj)
-
-
-def DELETE(request):
- """Delete this User."""
-
- request.check_required_parameters(path={'userId': 'string'})
-
- user = User.from_id(request.params_path['userId'])
-
- user.check_exists()
- user.check_correct_user(request.google_id)
-
- for authorization in user.obj['authorizations']:
- if authorization['authorizationLevel'] != 'OWN':
- continue
-
- project = Project.from_id(authorization['projectId'])
- project.delete()
-
- old_object = user.delete()
-
- return Response(200, 'Successfully deleted user.', old_object)
diff --git a/api/opendc/api/v2/users/userId/test_endpoint.py b/api/opendc/api/v2/users/userId/test_endpoint.py
deleted file mode 100644
index 4085642f..00000000
--- a/api/opendc/api/v2/users/userId/test_endpoint.py
+++ /dev/null
@@ -1,56 +0,0 @@
-from opendc.util.database import DB
-
-test_id = 24 * '1'
-
-
-def test_get_user_non_existing(client, mocker):
- mocker.patch.object(DB, 'fetch_one', return_value=None)
- assert '404' in client.get(f'/v2/users/{test_id}').status
-
-
-def test_get_user(client, mocker):
- mocker.patch.object(DB, 'fetch_one', return_value={'email': 'test@test.com'})
- res = client.get(f'/v2/users/{test_id}')
- assert 'email' in res.json['content']
- assert '200' in res.status
-
-
-def test_update_user_missing_parameter(client):
- assert '400' in client.put(f'/v2/users/{test_id}').status
-
-
-def test_update_user_non_existing(client, mocker):
- mocker.patch.object(DB, 'fetch_one', return_value=None)
- assert '404' in client.put(f'/v2/users/{test_id}', json={'user': {'givenName': 'A', 'familyName': 'B'}}).status
-
-
-def test_update_user_different_user(client, mocker):
- mocker.patch.object(DB, 'fetch_one', return_value={'_id': test_id, 'googleId': 'other_test'})
- assert '403' in client.put(f'/v2/users/{test_id}', json={'user': {'givenName': 'A', 'familyName': 'B'}}).status
-
-
-def test_update_user(client, mocker):
- mocker.patch.object(DB, 'fetch_one', return_value={'_id': test_id, 'googleId': 'test'})
- mocker.patch.object(DB, 'update', return_value={'givenName': 'A', 'familyName': 'B'})
- res = client.put(f'/v2/users/{test_id}', json={'user': {'givenName': 'A', 'familyName': 'B'}})
- assert 'givenName' in res.json['content']
- assert '200' in res.status
-
-
-def test_delete_user_non_existing(client, mocker):
- mocker.patch.object(DB, 'fetch_one', return_value=None)
- assert '404' in client.delete(f'/v2/users/{test_id}').status
-
-
-def test_delete_user_different_user(client, mocker):
- mocker.patch.object(DB, 'fetch_one', return_value={'_id': test_id, 'googleId': 'other_test'})
- assert '403' in client.delete(f'/v2/users/{test_id}').status
-
-
-def test_delete_user(client, mocker):
- mocker.patch.object(DB, 'fetch_one', return_value={'_id': test_id, 'googleId': 'test', 'authorizations': []})
- mocker.patch.object(DB, 'delete_one', return_value={'googleId': 'test'})
- res = client.delete(f'/v2/users/{test_id}', )
-
- assert 'googleId' in res.json['content']
- assert '200' in res.status
diff --git a/api/opendc/models/__init__.py b/api/opendc/models/__init__.py
deleted file mode 100644
index e69de29b..00000000
--- a/api/opendc/models/__init__.py
+++ /dev/null
diff --git a/api/opendc/models/model.py b/api/opendc/models/model.py
deleted file mode 100644
index f9dfc9ad..00000000
--- a/api/opendc/models/model.py
+++ /dev/null
@@ -1,64 +0,0 @@
-from bson.objectid import ObjectId
-
-from opendc.util.database import DB
-from opendc.util.exceptions import ClientError
-from opendc.util.rest import Response
-
-
-class Model:
- """Base class for all models."""
-
- collection_name = '<specified in subclasses>'
-
- @classmethod
- def from_id(cls, _id):
- """Fetches the document with given ID from the collection."""
- if isinstance(_id, str) and len(_id) == 24:
- _id = ObjectId(_id)
- elif not isinstance(_id, ObjectId):
- return cls(None)
-
- return cls(DB.fetch_one({'_id': _id}, cls.collection_name))
-
- @classmethod
- def get_all(cls):
- """Fetches all documents from the collection."""
- return cls(DB.fetch_all({}, cls.collection_name))
-
- def __init__(self, obj):
- self.obj = obj
-
- def get_id(self):
- """Returns the ID of the enclosed object."""
- return self.obj['_id']
-
- def check_exists(self):
- """Raises an error if the enclosed object does not exist."""
- if self.obj is None:
- raise ClientError(Response(404, 'Not found.'))
-
- def set_property(self, key, value):
- """Sets the given property on the enclosed object, with support for simple nested access."""
- if '.' in key:
- keys = key.split('.')
- self.obj[keys[0]][keys[1]] = value
- else:
- self.obj[key] = value
-
- def insert(self):
- """Inserts the enclosed object and generates a UUID for it."""
- self.obj['_id'] = ObjectId()
- DB.insert(self.obj, self.collection_name)
-
- def update(self):
- """Updates the enclosed object and updates the internal reference to the newly inserted object."""
- DB.update(self.get_id(), self.obj, self.collection_name)
-
- def delete(self):
- """Deletes the enclosed object in the database, if it existed."""
- if self.obj is None:
- return None
-
- old_object = self.obj.copy()
- DB.delete_one({'_id': self.get_id()}, self.collection_name)
- return old_object
diff --git a/api/opendc/models/portfolio.py b/api/opendc/models/portfolio.py
deleted file mode 100644
index 32961b63..00000000
--- a/api/opendc/models/portfolio.py
+++ /dev/null
@@ -1,24 +0,0 @@
-from opendc.models.model import Model
-from opendc.models.user import User
-from opendc.util.exceptions import ClientError
-from opendc.util.rest import Response
-
-
-class Portfolio(Model):
- """Model representing a Portfolio."""
-
- collection_name = 'portfolios'
-
- def check_user_access(self, google_id, edit_access):
- """Raises an error if the user with given [google_id] has insufficient access.
-
- Checks access on the parent project.
-
- :param google_id: The Google ID of the user.
- :param edit_access: True when edit access should be checked, otherwise view access.
- """
- user = User.from_google_id(google_id)
- authorizations = list(
- filter(lambda x: str(x['projectId']) == str(self.obj['projectId']), user.obj['authorizations']))
- if len(authorizations) == 0 or (edit_access and authorizations[0]['authorizationLevel'] == 'VIEW'):
- raise ClientError(Response(403, 'Forbidden from retrieving/editing portfolio.'))
diff --git a/api/opendc/models/prefab.py b/api/opendc/models/prefab.py
deleted file mode 100644
index edf1d4c4..00000000
--- a/api/opendc/models/prefab.py
+++ /dev/null
@@ -1,28 +0,0 @@
-from opendc.models.model import Model
-from opendc.models.user import User
-from opendc.util.exceptions import ClientError
-from opendc.util.rest import Response
-
-
-class Prefab(Model):
- """Model representing a Project."""
-
- collection_name = 'prefabs'
-
- def check_user_access(self, google_id):
- """Raises an error if the user with given [google_id] has insufficient access to view this prefab.
-
- :param google_id: The Google ID of the user.
- """
- user = User.from_google_id(google_id)
-
- # TODO(Jacob) add special handling for OpenDC-provided prefabs
-
- #try:
-
- print(self.obj)
- if self.obj['authorId'] != user.get_id() and self.obj['visibility'] == "private":
- raise ClientError(Response(403, "Forbidden from retrieving prefab."))
- #except KeyError:
- # OpenDC-authored objects don't necessarily have an authorId
- # return
diff --git a/api/opendc/models/project.py b/api/opendc/models/project.py
deleted file mode 100644
index b57e9f77..00000000
--- a/api/opendc/models/project.py
+++ /dev/null
@@ -1,31 +0,0 @@
-from opendc.models.model import Model
-from opendc.models.user import User
-from opendc.util.database import DB
-from opendc.util.exceptions import ClientError
-from opendc.util.rest import Response
-
-
-class Project(Model):
- """Model representing a Project."""
-
- collection_name = 'projects'
-
- def check_user_access(self, google_id, edit_access):
- """Raises an error if the user with given [google_id] has insufficient access.
-
- :param google_id: The Google ID of the user.
- :param edit_access: True when edit access should be checked, otherwise view access.
- """
- user = User.from_google_id(google_id)
- authorizations = list(filter(lambda x: str(x['projectId']) == str(self.get_id()),
- user.obj['authorizations']))
- if len(authorizations) == 0 or (edit_access and authorizations[0]['authorizationLevel'] == 'VIEW'):
- raise ClientError(Response(403, "Forbidden from retrieving project."))
-
- def get_all_authorizations(self):
- """Get all user IDs having access to this project."""
- return [
- str(user['_id']) for user in DB.fetch_all({'authorizations': {
- 'projectId': self.obj['_id']
- }}, User.collection_name)
- ]
diff --git a/api/opendc/models/scenario.py b/api/opendc/models/scenario.py
deleted file mode 100644
index 8d53e408..00000000
--- a/api/opendc/models/scenario.py
+++ /dev/null
@@ -1,26 +0,0 @@
-from opendc.models.model import Model
-from opendc.models.portfolio import Portfolio
-from opendc.models.user import User
-from opendc.util.exceptions import ClientError
-from opendc.util.rest import Response
-
-
-class Scenario(Model):
- """Model representing a Scenario."""
-
- collection_name = 'scenarios'
-
- def check_user_access(self, google_id, edit_access):
- """Raises an error if the user with given [google_id] has insufficient access.
-
- Checks access on the parent project.
-
- :param google_id: The Google ID of the user.
- :param edit_access: True when edit access should be checked, otherwise view access.
- """
- portfolio = Portfolio.from_id(self.obj['portfolioId'])
- user = User.from_google_id(google_id)
- authorizations = list(
- filter(lambda x: str(x['projectId']) == str(portfolio.obj['projectId']), user.obj['authorizations']))
- if len(authorizations) == 0 or (edit_access and authorizations[0]['authorizationLevel'] == 'VIEW'):
- raise ClientError(Response(403, 'Forbidden from retrieving/editing scenario.'))
diff --git a/api/opendc/models/topology.py b/api/opendc/models/topology.py
deleted file mode 100644
index cb4c4bab..00000000
--- a/api/opendc/models/topology.py
+++ /dev/null
@@ -1,27 +0,0 @@
-from opendc.models.model import Model
-from opendc.models.user import User
-from opendc.util.exceptions import ClientError
-from opendc.util.rest import Response
-
-
-class Topology(Model):
- """Model representing a Project."""
-
- collection_name = 'topologies'
-
- def check_user_access(self, google_id, edit_access):
- """Raises an error if the user with given [google_id] has insufficient access.
-
- Checks access on the parent project.
-
- :param google_id: The Google ID of the user.
- :param edit_access: True when edit access should be checked, otherwise view access.
- """
- user = User.from_google_id(google_id)
- if 'projectId' not in self.obj:
- raise ClientError(Response(400, 'Missing projectId in topology.'))
-
- authorizations = list(
- filter(lambda x: str(x['projectId']) == str(self.obj['projectId']), user.obj['authorizations']))
- if len(authorizations) == 0 or (edit_access and authorizations[0]['authorizationLevel'] == 'VIEW'):
- raise ClientError(Response(403, 'Forbidden from retrieving topology.'))
diff --git a/api/opendc/models/trace.py b/api/opendc/models/trace.py
deleted file mode 100644
index 2f6e4926..00000000
--- a/api/opendc/models/trace.py
+++ /dev/null
@@ -1,7 +0,0 @@
-from opendc.models.model import Model
-
-
-class Trace(Model):
- """Model representing a Trace."""
-
- collection_name = 'traces'
diff --git a/api/opendc/models/user.py b/api/opendc/models/user.py
deleted file mode 100644
index 8e8ff945..00000000
--- a/api/opendc/models/user.py
+++ /dev/null
@@ -1,36 +0,0 @@
-from opendc.models.model import Model
-from opendc.util.database import DB
-from opendc.util.exceptions import ClientError
-from opendc.util.rest import Response
-
-
-class User(Model):
- """Model representing a User."""
-
- collection_name = 'users'
-
- @classmethod
- def from_email(cls, email):
- """Fetches the user with given email from the collection."""
- return User(DB.fetch_one({'email': email}, User.collection_name))
-
- @classmethod
- def from_google_id(cls, google_id):
- """Fetches the user with given Google ID from the collection."""
- return User(DB.fetch_one({'googleId': google_id}, User.collection_name))
-
- def check_correct_user(self, request_google_id):
- """Raises an error if a user tries to modify another user.
-
- :param request_google_id:
- """
- if request_google_id is not None and self.obj['googleId'] != request_google_id:
- raise ClientError(Response(403, f'Forbidden from editing user with ID {self.obj["_id"]}.'))
-
- def check_already_exists(self):
- """Checks if the user already exists in the database."""
-
- existing_user = DB.fetch_one({'googleId': self.obj['googleId']}, self.collection_name)
-
- if existing_user is not None:
- raise ClientError(Response(409, 'User already exists.'))
diff --git a/api/opendc/util/__init__.py b/api/opendc/util/__init__.py
deleted file mode 100644
index e69de29b..00000000
--- a/api/opendc/util/__init__.py
+++ /dev/null
diff --git a/api/opendc/util/database.py b/api/opendc/util/database.py
deleted file mode 100644
index dd26533d..00000000
--- a/api/opendc/util/database.py
+++ /dev/null
@@ -1,77 +0,0 @@
-import urllib.parse
-from datetime import datetime
-
-from pymongo import MongoClient
-
-DATETIME_STRING_FORMAT = '%Y-%m-%dT%H:%M:%S'
-CONNECTION_POOL = None
-
-
-class Database:
- """Object holding functionality for database access."""
- def __init__(self):
- self.opendc_db = None
-
- def initialize_database(self, user, password, database, host):
- """Initializes the database connection."""
-
- user = urllib.parse.quote_plus(user)
- password = urllib.parse.quote_plus(password)
- database = urllib.parse.quote_plus(database)
- host = urllib.parse.quote_plus(host)
-
- client = MongoClient('mongodb://%s:%s@%s/default_db?authSource=%s' % (user, password, host, database))
- self.opendc_db = client.opendc
-
- def fetch_one(self, query, collection):
- """Uses existing mongo connection to return a single (the first) document in a collection matching the given
- query as a JSON object.
-
- The query needs to be in json format, i.e.: `{'name': prefab_name}`.
- """
- return getattr(self.opendc_db, collection).find_one(query)
-
- def fetch_all(self, query, collection):
- """Uses existing mongo connection to return all documents matching a given query, as a list of JSON objects.
-
- The query needs to be in json format, i.e.: `{'name': prefab_name}`.
- """
- cursor = getattr(self.opendc_db, collection).find(query)
- return list(cursor)
-
- def insert(self, obj, collection):
- """Updates an existing object."""
- bson = getattr(self.opendc_db, collection).insert(obj)
-
- return bson
-
- def update(self, _id, obj, collection):
- """Updates an existing object."""
- return getattr(self.opendc_db, collection).update({'_id': _id}, obj)
-
- def delete_one(self, query, collection):
- """Deletes one object matching the given query.
-
- The query needs to be in json format, i.e.: `{'name': prefab_name}`.
- """
- getattr(self.opendc_db, collection).delete_one(query)
-
- def delete_all(self, query, collection):
- """Deletes all objects matching the given query.
-
- The query needs to be in json format, i.e.: `{'name': prefab_name}`.
- """
- getattr(self.opendc_db, collection).delete_many(query)
-
- @staticmethod
- def datetime_to_string(datetime_to_convert):
- """Return a database-compatible string representation of the given datetime object."""
- return datetime_to_convert.strftime(DATETIME_STRING_FORMAT)
-
- @staticmethod
- def string_to_datetime(string_to_convert):
- """Return a datetime corresponding to the given string representation."""
- return datetime.strptime(string_to_convert, DATETIME_STRING_FORMAT)
-
-
-DB = Database()
diff --git a/api/opendc/util/exceptions.py b/api/opendc/util/exceptions.py
deleted file mode 100644
index 7724a407..00000000
--- a/api/opendc/util/exceptions.py
+++ /dev/null
@@ -1,64 +0,0 @@
-class RequestInitializationError(Exception):
- """Raised when a Request cannot successfully be initialized"""
-
-
-class UnimplementedEndpointError(RequestInitializationError):
- """Raised when a Request path does not point to a module."""
-
-
-class MissingRequestParameterError(RequestInitializationError):
- """Raised when a Request does not contain one or more required parameters."""
-
-
-class UnsupportedMethodError(RequestInitializationError):
- """Raised when a Request does not use a supported REST method.
-
- The method must be in all-caps, supported by REST, and implemented by the module.
- """
-
-
-class AuthorizationTokenError(RequestInitializationError):
- """Raised when an authorization token is not correctly verified."""
-
-
-class ForeignKeyError(Exception):
- """Raised when a foreign key constraint is not met."""
-
-
-class RowNotFoundError(Exception):
- """Raised when a database row is not found."""
- def __init__(self, table_name):
- super(RowNotFoundError, self).__init__('Row in `{}` table not found.'.format(table_name))
-
- self.table_name = table_name
-
-
-class ParameterError(Exception):
- """Raised when a parameter is either missing or incorrectly typed."""
-
-
-class IncorrectParameterError(ParameterError):
- """Raised when a parameter is of the wrong type."""
- def __init__(self, parameter_name, parameter_location):
- super(IncorrectParameterError,
- self).__init__('Incorrectly typed `{}` {} parameter.'.format(parameter_name, parameter_location))
-
- self.parameter_name = parameter_name
- self.parameter_location = parameter_location
-
-
-class MissingParameterError(ParameterError):
- """Raised when a parameter is missing."""
- def __init__(self, parameter_name, parameter_location):
- super(MissingParameterError,
- self).__init__('Missing required `{}` {} parameter.'.format(parameter_name, parameter_location))
-
- self.parameter_name = parameter_name
- self.parameter_location = parameter_location
-
-
-class ClientError(Exception):
- """Raised when a 4xx response is to be returned."""
- def __init__(self, response):
- super(ClientError, self).__init__(str(response))
- self.response = response
diff --git a/api/opendc/util/json.py b/api/opendc/util/json.py
deleted file mode 100644
index 2ef4f965..00000000
--- a/api/opendc/util/json.py
+++ /dev/null
@@ -1,12 +0,0 @@
-import flask
-from bson.objectid import ObjectId
-
-
-class JSONEncoder(flask.json.JSONEncoder):
- """
- A customized JSON encoder to handle unsupported types.
- """
- def default(self, o):
- if isinstance(o, ObjectId):
- return str(o)
- return flask.json.JSONEncoder.default(self, o)
diff --git a/api/opendc/util/parameter_checker.py b/api/opendc/util/parameter_checker.py
deleted file mode 100644
index 14dd1dc0..00000000
--- a/api/opendc/util/parameter_checker.py
+++ /dev/null
@@ -1,85 +0,0 @@
-from opendc.util import exceptions
-from opendc.util.database import Database
-
-
-def _missing_parameter(params_required, params_actual, parent=''):
- """Recursively search for the first missing parameter."""
-
- for param_name in params_required:
-
- if param_name not in params_actual:
- return '{}.{}'.format(parent, param_name)
-
- param_required = params_required.get(param_name)
- param_actual = params_actual.get(param_name)
-
- if isinstance(param_required, dict):
-
- param_missing = _missing_parameter(param_required, param_actual, param_name)
-
- if param_missing is not None:
- return '{}.{}'.format(parent, param_missing)
-
- return None
-
-
-def _incorrect_parameter(params_required, params_actual, parent=''):
- """Recursively make sure each parameter is of the correct type."""
-
- for param_name in params_required:
-
- param_required = params_required.get(param_name)
- param_actual = params_actual.get(param_name)
-
- if isinstance(param_required, dict):
-
- param_incorrect = _incorrect_parameter(param_required, param_actual, param_name)
-
- if param_incorrect is not None:
- return '{}.{}'.format(parent, param_incorrect)
-
- else:
-
- if param_required == 'datetime':
- try:
- Database.string_to_datetime(param_actual)
- except:
- return '{}.{}'.format(parent, param_name)
-
- type_pairs = [
- ('int', (int,)),
- ('float', (float, int)),
- ('bool', (bool,)),
- ('string', (str, int)),
- ('list', (list,)),
- ]
-
- for str_type, actual_types in type_pairs:
- if param_required == str_type and all(not isinstance(param_actual, t)
- for t in actual_types):
- return '{}.{}'.format(parent, param_name)
-
- return None
-
-
-def _format_parameter(parameter):
- """Format the output of a parameter check."""
-
- parts = parameter.split('.')
- inner = ['["{}"]'.format(x) for x in parts[2:]]
- return parts[1] + ''.join(inner)
-
-
-def check(request, **kwargs):
- """Check if all required parameters are there."""
-
- for location, params_required in kwargs.items():
- params_actual = getattr(request, 'params_{}'.format(location))
-
- missing_parameter = _missing_parameter(params_required, params_actual)
- if missing_parameter is not None:
- raise exceptions.MissingParameterError(_format_parameter(missing_parameter), location)
-
- incorrect_parameter = _incorrect_parameter(params_required, params_actual)
- if incorrect_parameter is not None:
- raise exceptions.IncorrectParameterError(_format_parameter(incorrect_parameter), location)
diff --git a/api/opendc/util/path_parser.py b/api/opendc/util/path_parser.py
deleted file mode 100644
index c8452f20..00000000
--- a/api/opendc/util/path_parser.py
+++ /dev/null
@@ -1,36 +0,0 @@
-import json
-import os
-
-
-def parse(version, endpoint_path):
- """Map an HTTP endpoint path to an API path"""
-
- # Get possible paths
- with open(os.path.join(os.path.dirname(__file__), '..', 'api', '{}', 'paths.json').format(version)) as paths_file:
- paths = json.load(paths_file)
-
- # Find API path that matches endpoint_path
- endpoint_path_parts = endpoint_path.strip('/').split('/')
- paths_parts = [x.strip('/').split('/') for x in paths if len(x.strip('/').split('/')) == len(endpoint_path_parts)]
- path = None
-
- for path_parts in paths_parts:
- found = True
- for (endpoint_part, part) in zip(endpoint_path_parts, path_parts):
- if not part.startswith('{') and endpoint_part != part:
- found = False
- break
- if found:
- path = path_parts
-
- if path is None:
- return None
-
- # Extract path parameters
- parameters = {}
-
- for (name, value) in zip(path, endpoint_path_parts):
- if name.startswith('{'):
- parameters[name.strip('{}')] = value
-
- return '{}/{}'.format(version, '/'.join(path)), parameters
diff --git a/api/opendc/util/rest.py b/api/opendc/util/rest.py
deleted file mode 100644
index c9e98295..00000000
--- a/api/opendc/util/rest.py
+++ /dev/null
@@ -1,141 +0,0 @@
-import importlib
-import json
-import os
-
-from oauth2client import client, crypt
-
-from opendc.util import exceptions, parameter_checker
-from opendc.util.exceptions import ClientError
-
-
-class Request:
- """WebSocket message to REST request mapping."""
- def __init__(self, message=None):
- """"Initialize a Request from a socket message."""
-
- # Get the Request parameters from the message
-
- if message is None:
- return
-
- try:
- self.message = message
-
- self.id = message['id']
-
- self.path = message['path']
- self.method = message['method']
-
- self.params_body = message['parameters']['body']
- self.params_path = message['parameters']['path']
- self.params_query = message['parameters']['query']
-
- self.token = message['token']
-
- except KeyError as exception:
- raise exceptions.MissingRequestParameterError(exception)
-
- # Parse the path and import the appropriate module
-
- try:
- self.path = message['path'].strip('/')
-
- module_base = 'opendc.api.{}.endpoint'
- module_path = self.path.replace('{', '').replace('}', '').replace('/', '.')
-
- self.module = importlib.import_module(module_base.format(module_path))
- except ImportError as e:
- print(e)
- raise exceptions.UnimplementedEndpointError('Unimplemented endpoint: {}.'.format(self.path))
-
- # Check the method
-
- if self.method not in ['POST', 'GET', 'PUT', 'PATCH', 'DELETE']:
- raise exceptions.UnsupportedMethodError('Non-rest method: {}'.format(self.method))
-
- if not hasattr(self.module, self.method):
- raise exceptions.UnsupportedMethodError('Unimplemented method at endpoint {}: {}'.format(
- self.path, self.method))
-
- # Verify the user
-
- if "OPENDC_FLASK_TESTING" in os.environ:
- self.google_id = 'test'
- return
-
- try:
- self.google_id = self._verify_token(self.token)
- except crypt.AppIdentityError as e:
- raise exceptions.AuthorizationTokenError(e)
-
- def check_required_parameters(self, **kwargs):
- """Raise an error if a parameter is missing or of the wrong type."""
-
- try:
- parameter_checker.check(self, **kwargs)
- except exceptions.ParameterError as e:
- raise ClientError(Response(400, str(e)))
-
- def process(self):
- """Process the Request and return a Response."""
-
- method = getattr(self.module, self.method)
-
- try:
- response = method(self)
- except ClientError as e:
- e.response.id = self.id
- return e.response
-
- response.id = self.id
-
- return response
-
- def to_JSON(self):
- """Return a JSON representation of this Request"""
-
- self.message['id'] = 0
- self.message['token'] = None
-
- return json.dumps(self.message)
-
- @staticmethod
- def _verify_token(token):
- """Return the ID of the signed-in user.
-
- Or throw an Exception if the token is invalid.
- """
-
- try:
- id_info = client.verify_id_token(token, os.environ['OPENDC_OAUTH_CLIENT_ID'])
- except Exception as e:
- print(e)
- raise crypt.AppIdentityError('Exception caught trying to verify ID token: {}'.format(e))
-
- if id_info['aud'] != os.environ['OPENDC_OAUTH_CLIENT_ID']:
- raise crypt.AppIdentityError('Unrecognized client.')
-
- if id_info['iss'] not in ['accounts.google.com', 'https://accounts.google.com']:
- raise crypt.AppIdentityError('Wrong issuer.')
-
- return id_info['sub']
-
-
-class Response:
- """Response to websocket mapping"""
- def __init__(self, status_code, status_description, content=None):
- """Initialize a new Response."""
-
- self.id = 0
- self.status = {'code': status_code, 'description': status_description}
- self.content = content
-
- def to_JSON(self):
- """"Return a JSON representation of this Response"""
-
- data = {'id': self.id, 'status': self.status}
-
- if self.content is not None:
- data['content'] = self.content
-
- return json.dumps(data, default=str)
diff --git a/api/pytest.ini b/api/pytest.ini
deleted file mode 100644
index 8e7964ba..00000000
--- a/api/pytest.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[pytest]
-env =
- OPENDC_FLASK_TESTING=True
- OPENDC_FLASK_SECRET=Secret
-junit_family = xunit2
diff --git a/api/requirements.txt b/api/requirements.txt
deleted file mode 100644
index d95a8d83..00000000
--- a/api/requirements.txt
+++ /dev/null
@@ -1,47 +0,0 @@
-astroid==2.4.2
-attrs==20.3.0
-blinker==1.4
-Brotli==1.0.9
-certifi==2020.11.8
-click==7.1.2
-dnspython==2.0.0
-eventlet==0.25.2
-Flask==1.1.2
-Flask-Compress==1.5.0
-Flask-Cors==3.0.8
-Flask-SocketIO==4.3.1
-greenlet==0.4.17
-httplib2==0.19.0
-isort==4.3.21
-itsdangerous==1.1.0
-Jinja2==2.11.3
-lazy-object-proxy==1.4.3
-MarkupSafe==1.1.1
-mccabe==0.6.1
-monotonic==1.5
-more-itertools==8.6.0
-oauth2client==4.1.3
-packaging==20.4
-pluggy==0.13.1
-py==1.10.0
-pyasn1==0.4.8
-pyasn1-modules==0.2.8
-pylint==2.5.3
-pymongo==3.10.1
-pyparsing==2.4.7
-pytest==5.4.3
-pytest-cov==2.11.1
-pytest-env==0.6.2
-pytest-mock==3.2.0
-python-dotenv==0.14.0
-python-engineio==3.13.2
-python-socketio==4.6.0
-rsa==4.6
-sentry-sdk==0.19.2
-six==1.15.0
-toml==0.10.2
-urllib3==1.26.4
-wcwidth==0.2.5
-Werkzeug==1.0.1
-wrapt==1.12.1
-yapf==0.30.0
diff --git a/api/static/index.html b/api/static/index.html
deleted file mode 100644
index ac78cbfb..00000000
--- a/api/static/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-<script src="https://apis.google.com/js/platform.js" async defer></script>
-<meta name="google-signin-client_id" content="561588943542-fq7065hk47qdf3lfsc50ebll4spi6u76.apps.googleusercontent.com">
-<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/socket.io/1.3.6/socket.io.min.js"></script>
-<script>
- function onSignIn(googleUser) {
- document.getElementById('token').innerText = googleUser.getAuthResponse().id_token;
- }
-</script>
-<script>
- function signOut() {
- var auth2 = gapi.auth2.getAuthInstance();
- auth2.signOut().then(function () {
- console.log('User signed out.');
- });
- }
-</script>
-
-<div class="g-signin2" data-onsuccess="onSignIn"></div>
-<a href="#" onclick="signOut();">Sign out</a>
-
-<p>Your auth token:</p>
-<p id="token" style="word-wrap:break-word;">Loading...</p> \ No newline at end of file