kopia lustrzana https://github.com/kprestel/nextcloud-deck
commit
c106dccfae
|
@ -0,0 +1,34 @@
|
|||
name: CI
|
||||
on: push
|
||||
|
||||
jobs:
|
||||
ci:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
python-version: [3.8, 3.9]
|
||||
poetry-version: [1.1.6]
|
||||
os: [ubuntu-18.04]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
- uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
- name: Run image
|
||||
uses: abatilo/actions-poetry@v2.0.0
|
||||
with:
|
||||
poetry-version: ${{ matrix.poetry-version }}
|
||||
- name: build package
|
||||
run: >-
|
||||
poetry build
|
||||
- name: Publish distribution 📦 to Test PyPI
|
||||
uses: pypa/gh-action-pypi-publish@master
|
||||
with:
|
||||
password: ${{ secrets.TEST_PYPI_API_TOKEN }}
|
||||
repository_url: https://test.pypi.org/legacy/
|
||||
- name: Publish distribution 📦 to PyPI
|
||||
if: startsWith(github.ref, 'refs/tags')
|
||||
uses: pypa/gh-action-pypi-publish@master
|
||||
with:
|
||||
password: ${{ secrets.PYPI_API_TOKEN }}
|
|
@ -1,4 +1,137 @@
|
|||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
pip-wheel-metadata/
|
||||
share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.nox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
*.py,cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
db.sqlite3-journal
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# IPython
|
||||
profile_default/
|
||||
ipython_config.py
|
||||
|
||||
# pyenv
|
||||
.python-version
|
||||
|
||||
# pipenv
|
||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||
# install all needed dependencies.
|
||||
#Pipfile.lock
|
||||
|
||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
||||
__pypackages__/
|
||||
|
||||
# Celery stuff
|
||||
celerybeat-schedule
|
||||
celerybeat.pid
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
.dmypy.json
|
||||
dmypy.json
|
||||
|
||||
# Pyre type checker
|
||||
.pyre/
|
||||
|
||||
# Project specific
|
||||
.idea
|
||||
test/data
|
||||
test/config
|
||||
test/.pytest_cache
|
||||
venv
|
||||
.tox
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
FROM ghcr.io/linuxserver/nextcloud
|
||||
COPY test/data /data
|
||||
COPY test/config /config
|
||||
COPY tests/data /data
|
||||
COPY tests/config /config
|
||||
|
|
16
Makefile
16
Makefile
|
@ -1,5 +1,5 @@
|
|||
.PHONY: clean-pyc test clean-build
|
||||
TEST_PATH=tests
|
||||
TEST_PATH=test
|
||||
|
||||
clean-pyc:
|
||||
find . -name '*.pyc' -exec rm --force {} +
|
||||
|
@ -20,12 +20,12 @@ isort:
|
|||
lint:
|
||||
flake8 --exclude=.tox
|
||||
|
||||
test: clean-pyc
|
||||
test: clean-pyc build-test start-nextcloud-test-instance
|
||||
tox
|
||||
|
||||
black:
|
||||
black deck/
|
||||
black test/
|
||||
black tests/
|
||||
|
||||
create-volumes:
|
||||
docker volume create nextcloud-data
|
||||
|
@ -34,10 +34,18 @@ create-volumes:
|
|||
build-test-image:
|
||||
docker build -t nextcloud-test .
|
||||
|
||||
build-test: create-volumes build-test-image
|
||||
|
||||
build:
|
||||
poetry build
|
||||
|
||||
deploy: build
|
||||
poetry publish
|
||||
|
||||
publish: deploy
|
||||
publish: deploy
|
||||
|
||||
start-nextcloud-test-instance:
|
||||
./bin/start-nextcloud.sh
|
||||
|
||||
install-deck:
|
||||
docker exec --user www-data nextcloud php occ app:install deck
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# Python Nextcloud Deck API
|
||||
|
||||
Simple python based wrapper around the Nextcloud deck API
|
||||
Simple python based wrapper around the Nextcloud deck API
|
||||
|
||||
Before using this library you should get familiar with the [Offical REST API](https://deck.readthedocs.io/en/latest/API/)
|
|
@ -4,6 +4,9 @@ docker run -d \
|
|||
-e PUID=1000 \
|
||||
-e PGID=1001 \
|
||||
-e TZ=Europe/London \
|
||||
-e NEXTCLOUD_ADMIN_USER=Admin \
|
||||
-e NEXTCLOUD_ADMIN_PASSWORD=admin \
|
||||
-e SQLITE_DATABASE=nextcloud-deck-test \
|
||||
-p 443:443 \
|
||||
-v nextcloud-config:/config \
|
||||
-v nextcloud-data:/data \
|
||||
|
|
210
deck/api.py
210
deck/api.py
|
@ -8,8 +8,11 @@ from deck.models import Board, Card, Label, Stack, deserialize
|
|||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
IdType = typing.Union[int, str]
|
||||
|
||||
|
||||
class NextCloudDeckAPI:
|
||||
"""docstring for NextCloudDeck."""
|
||||
"""Wrapper around the NextCloud Deck API"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
|
@ -38,6 +41,14 @@ class NextCloudDeckAPI:
|
|||
)
|
||||
return response.json()
|
||||
|
||||
@deserialize(Board)
|
||||
def create_board(self, title, color="ff0000") -> Board:
|
||||
logger.info(f"Creating board with title: {title} and color: {color}")
|
||||
response = self.session.post(
|
||||
f"{self.url}", json={"title": title, "color": color}
|
||||
)
|
||||
return response.json()
|
||||
|
||||
@deserialize(Board)
|
||||
def get_board(self, board_id) -> Board:
|
||||
response = self.session.get(
|
||||
|
@ -45,6 +56,72 @@ class NextCloudDeckAPI:
|
|||
)
|
||||
return response.json()
|
||||
|
||||
def update_board(
|
||||
self, board_id: IdType, title: str, color: str, archived: bool
|
||||
) -> typing.Dict[str, typing.Any]:
|
||||
response = self.session.put(
|
||||
f"{self.url}/boards/{board_id}",
|
||||
json={"title": title, "color": color, "archived": archived},
|
||||
)
|
||||
return response.json()
|
||||
|
||||
def delete_board(self, board_id):
|
||||
logger.info(f"Deleting board with ID: {board_id}")
|
||||
response = self.session.delete(f"{self.url}/{board_id}")
|
||||
logger.debug(response)
|
||||
return response.json()
|
||||
|
||||
def undo_delete_board(self, board_id: IdType) -> typing.Dict[str, typing.Any]:
|
||||
response = self.session.post(f"{self.url}/boards/{board_id}/undo_delete")
|
||||
return response.json()
|
||||
|
||||
def add_board_acl_rule(
|
||||
self,
|
||||
board_id: IdType,
|
||||
type: int,
|
||||
participant: str,
|
||||
perm_edit: bool,
|
||||
perm_share: bool,
|
||||
perm_manage: bool,
|
||||
):
|
||||
response = self.session.post(
|
||||
f"{self.url}/boards/{board_id}/acl",
|
||||
json={
|
||||
"type": type,
|
||||
"participant": participant,
|
||||
"permissionEdit": perm_edit,
|
||||
"permissionShare": perm_share,
|
||||
"permissionManage": perm_manage,
|
||||
},
|
||||
)
|
||||
return response.json() # TODO: Deserialization to model for ACL rule
|
||||
|
||||
def update_board_acl_rule(
|
||||
self,
|
||||
board_id: IdType,
|
||||
acl_id: IdType,
|
||||
perm_edit: bool,
|
||||
perm_share: bool,
|
||||
perm_manage: bool,
|
||||
) -> typing.Dict[str, typing.Any]:
|
||||
response = self.session.put(
|
||||
f"{self.url}/boards/{board_id}/acl/{acl_id}",
|
||||
json={
|
||||
"permissionEdit": perm_edit,
|
||||
"permissionShare": perm_share,
|
||||
"permissionManage": perm_manage,
|
||||
},
|
||||
)
|
||||
return response.json()
|
||||
|
||||
def delete_board_acl_rule(
|
||||
self, board_id: IdType, acl_id: IdType
|
||||
) -> typing.Dict[str, typing.Any]:
|
||||
response = self.session.delete(f"{self.url}/boards/{board_id}/acl/{acl_id}")
|
||||
return response.json()
|
||||
|
||||
# Stacks
|
||||
|
||||
@deserialize(typing.List[Stack])
|
||||
def get_stacks(self, board_id):
|
||||
response = self.session.get(
|
||||
|
@ -52,6 +129,36 @@ class NextCloudDeckAPI:
|
|||
)
|
||||
return response.json()
|
||||
|
||||
@deserialize(typing.List[Stack])
|
||||
def get_archived_stacks(self, board_id: IdType) -> typing.Dict[str, typing.Any]:
|
||||
response = self.session.get(f"{self.url}/{board_id}/stacks/archived")
|
||||
return response.json()
|
||||
|
||||
@deserialize(Stack)
|
||||
def get_stack(self, board_id: IdType, stack_id: IdType):
|
||||
response = self.session.get(f"{self.url}/{board_id}/stacks/{stack_id}")
|
||||
return response.json()
|
||||
|
||||
@deserialize(Stack)
|
||||
def create_stack(self, board_id, title, order=999):
|
||||
response = self.session.post(
|
||||
f"{self.url}/{board_id}/stacks",
|
||||
json={"title": title, "order": order},
|
||||
)
|
||||
return response.json()
|
||||
|
||||
def update_stack(self, board_id: IdType, stack_id: IdType, title: str, order: int):
|
||||
response = self.session.put(
|
||||
f"{self.url}/{board_id}/stacks/{stack_id}",
|
||||
json={"title": title, "order": order},
|
||||
)
|
||||
return response.json()
|
||||
|
||||
@deserialize(Stack)
|
||||
def delete_stack(self, board_id, stack_id):
|
||||
response = self.session.delete(f"{self.url}/{board_id}/stacks/{stack_id}")
|
||||
return response.json()
|
||||
|
||||
@deserialize(typing.List[Card])
|
||||
def get_cards_from_stack(self, board_id, stack_id):
|
||||
response = self.session.get(
|
||||
|
@ -61,6 +168,8 @@ class NextCloudDeckAPI:
|
|||
return response.json()["cards"]
|
||||
return []
|
||||
|
||||
# Cards
|
||||
|
||||
@deserialize(Card)
|
||||
def get_card(self, board_id, stack_id, card_id):
|
||||
response = self.session.get(
|
||||
|
@ -68,27 +177,6 @@ class NextCloudDeckAPI:
|
|||
)
|
||||
return response.json()
|
||||
|
||||
@deserialize(Label)
|
||||
def create_label(self, board_id, title, color="ff0000"):
|
||||
response = self.session.post(
|
||||
f"{self.url}/{board_id}/labels",
|
||||
json={"title": title, "color": color},
|
||||
)
|
||||
return response.json()
|
||||
|
||||
@deserialize(Stack)
|
||||
def create_stack(self, board_id, title, order=999):
|
||||
response = self.session.post(
|
||||
f"{self.url}/{board_id}/stacks",
|
||||
json={"title": title, "order": order},
|
||||
)
|
||||
return response.json()
|
||||
|
||||
@deserialize(Stack)
|
||||
def delete_stack(self, board_id, stack_id):
|
||||
response = self.session.delete(f"{self.url}/{board_id}/stacks/{stack_id}")
|
||||
return response.json()
|
||||
|
||||
@deserialize(Card)
|
||||
def create_card(
|
||||
self,
|
||||
|
@ -141,13 +229,8 @@ class NextCloudDeckAPI:
|
|||
response = self.session.delete(
|
||||
f"{self.url}/{board_id}/stacks/{stack_id}/cards/{card_id}"
|
||||
)
|
||||
|
||||
return response.json()
|
||||
|
||||
def get_labels(self, board_id):
|
||||
boards = self.get_board(board_id)
|
||||
return boards.labels
|
||||
|
||||
def remove_label_from_card(self, board_id, stack_id, card_id, label_id):
|
||||
logger.info(
|
||||
f"removing label: board_id: {board_id}, stack_id: {stack_id}, card_id: {card_id}, label_id: {label_id}"
|
||||
|
@ -158,12 +241,8 @@ class NextCloudDeckAPI:
|
|||
)
|
||||
return response.json()
|
||||
|
||||
def delete_label(self, board_id, label_id):
|
||||
response = self.session.delete(f"{self.url}/{board_id}/labels/{label_id}")
|
||||
return response.json()
|
||||
|
||||
def assign_label_to_card(
|
||||
self, label_id, card_id, board_id, stack_id
|
||||
self, board_id, stack_id, card_id, label_id
|
||||
) -> typing.Dict[str, typing.Any]:
|
||||
response = self.session.put(
|
||||
f"{self.url}/{board_id}/stacks/{stack_id}/cards/{card_id}/assignLabel",
|
||||
|
@ -171,16 +250,65 @@ class NextCloudDeckAPI:
|
|||
)
|
||||
return response.json()
|
||||
|
||||
@deserialize(Board)
|
||||
def create_board(self, title, color="ff0000") -> Board:
|
||||
logger.info(f"Creating board with title: {title} and color: {color}")
|
||||
response = self.session.post(
|
||||
f"{self.url}", json={"title": title, "color": color}
|
||||
def assign_user_to_card(
|
||||
self, board_id, stack_id, card_id, user_id
|
||||
) -> typing.Dict[str, typing.Any]:
|
||||
response = self.session.put(
|
||||
f"{self.url}/{board_id}/stacks/{stack_id}/cards/{card_id}/assignUser",
|
||||
json={"userId": user_id},
|
||||
)
|
||||
return response.json()
|
||||
|
||||
def delete_board(self, board_id):
|
||||
logger.info(f"Deleting board with ID: {board_id}")
|
||||
response = self.session.delete(f"{self.url}/{board_id}")
|
||||
logger.debug(response)
|
||||
def unassign_user_from_card(
|
||||
self, board_id, stack_id, card_id, user_id
|
||||
) -> typing.Dict[str, typing.Any]:
|
||||
response = self.session.put(
|
||||
f"{self.url}/{board_id}/stacks/{stack_id}/cards/{card_id}/unassignUser",
|
||||
json={"userId": user_id},
|
||||
)
|
||||
return response.json()
|
||||
|
||||
def reorder_card(
|
||||
self, board_id, stack_id, card_id, order, stack_target
|
||||
) -> typing.Dict[str, typing.Any]:
|
||||
response = self.session.put(
|
||||
f"{self.url}/{board_id}/stacks/{stack_id}/cards/{card_id}/reorder",
|
||||
json={"order": order, "stackId": stack_target},
|
||||
)
|
||||
return response.json()
|
||||
|
||||
# Labels
|
||||
|
||||
@deserialize(Label)
|
||||
def get_label(
|
||||
self, board_id: IdType, label_id: IdType
|
||||
) -> typing.Dict[str, typing.Any]:
|
||||
response = self.session.get(f"{self.url}/{board_id}/labels/{label_id}")
|
||||
return response.json()
|
||||
|
||||
@deserialize(Label)
|
||||
def create_label(self, board_id, title, color="ff0000"):
|
||||
response = self.session.post(
|
||||
f"{self.url}/{board_id}/labels",
|
||||
json={"title": title, "color": color},
|
||||
)
|
||||
return response.json()
|
||||
|
||||
def update_label(
|
||||
self, board_id: IdType, label_id: IdType, title: str, color: str
|
||||
) -> typing.Dict[str, typing.Any]:
|
||||
response = self.session.put(
|
||||
f"{self.url}/{board_id}/labels/{label_id}",
|
||||
json={"title": title, "color": color},
|
||||
)
|
||||
return response.json()
|
||||
|
||||
def delete_label(
|
||||
self, board_id: IdType, label_id: IdType
|
||||
) -> typing.Dict[str, typing.Any]:
|
||||
response = self.session.delete(f"{self.url}/{board_id}/labels/{label_id}")
|
||||
return response.json()
|
||||
|
||||
def get_board_labels(self, board_id: IdType):
|
||||
boards = self.get_board(board_id)
|
||||
return boards.labels
|
||||
|
|
|
@ -5,7 +5,6 @@ import typing
|
|||
|
||||
import attr
|
||||
import cattr
|
||||
import dateutil
|
||||
from cattr.preconf.json import make_converter
|
||||
from dateutil.parser import parse
|
||||
|
||||
|
@ -17,7 +16,7 @@ T = typing.TypeVar("T")
|
|||
|
||||
|
||||
def to_snake(s):
|
||||
return re.sub("([A-Z]\w+$)", "_\\1", s).lower()
|
||||
return re.sub(r"([A-Z]\w+$)", "_\\1", s).lower()
|
||||
|
||||
|
||||
def json_to_snake(d):
|
||||
|
@ -30,10 +29,10 @@ def json_to_snake(d):
|
|||
}
|
||||
|
||||
|
||||
def deserialize(model: typing.Generic[T]) -> T:
|
||||
def deserialize(model: typing.Generic[T]) -> typing.Callable:
|
||||
def outer(fn):
|
||||
@functools.wraps(fn)
|
||||
def inner(*args, **kwargs):
|
||||
def inner(*args, **kwargs) -> T:
|
||||
json_ = fn(*args, **kwargs)
|
||||
json_ = json_to_snake(json_)
|
||||
return cattr.structure(json_, model)
|
||||
|
@ -71,8 +70,8 @@ class Card:
|
|||
archived: bool
|
||||
notified: bool = False
|
||||
deleted_at: int = 0
|
||||
duedate: str = None
|
||||
description: str = None
|
||||
duedate: typing.Optional[str] = None
|
||||
description: typing.Optional[str] = None
|
||||
type: str = "plain"
|
||||
labels: typing.Optional[typing.List[Label]] = attr.Factory(list)
|
||||
|
||||
|
|
Plik diff jest za duży
Load Diff
|
@ -2,6 +2,9 @@
|
|||
name = "nextcloud-deck"
|
||||
version = "0.1.0"
|
||||
description = "Python wrapper around Nextcloud Deck API"
|
||||
readme = "README.md"
|
||||
repository = "https://github.com/kprestel/nextcloud-deck"
|
||||
keywords = ["nextcloud"]
|
||||
authors = ["Kyle Prestel <kprestel@gmail.com>"]
|
||||
license = "MIT"
|
||||
packages = [
|
||||
|
@ -9,7 +12,7 @@ packages = [
|
|||
]
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.9"
|
||||
python = "^3.8"
|
||||
requests = "^2.25.1"
|
||||
attrs = "^21.2.0"
|
||||
cattrs = "^1.7.1"
|
||||
|
@ -17,11 +20,12 @@ dateutils = "^0.6.12"
|
|||
|
||||
[tool.poetry.dev-dependencies]
|
||||
pytest = "^6.2.4"
|
||||
black = "^21.6b0"
|
||||
black = { version = "*", allow-prereleases = true }
|
||||
mypy = "^0.902"
|
||||
isort = "^5.8.0"
|
||||
tox = "^3.23.1"
|
||||
tox-poetry = "^0.4.0"
|
||||
flake8-black = "^0.2.1"
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry>=0.12"]
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import cattr
|
||||
import pytest
|
||||
from requests.auth import HTTPBasicAuth
|
||||
|
||||
|
@ -9,7 +8,7 @@ from deck.models import Board, Card, Stack
|
|||
@pytest.fixture(scope="session")
|
||||
def nc() -> NextCloudDeckAPI:
|
||||
return NextCloudDeckAPI(
|
||||
"https://localhost:443", HTTPBasicAuth("kp", "asdf"), ssl_verify=False
|
||||
"https://localhost:443", HTTPBasicAuth("Admin", "admin"), ssl_verify=False
|
||||
)
|
||||
|
||||
|
||||
|
@ -27,6 +26,13 @@ def stack(nc, board: Board):
|
|||
nc.delete_stack(board_id=board.id, stack_id=s.id)
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def stack2(nc, board: Board):
|
||||
s = nc.create_stack(board.id, "test stack 2")
|
||||
yield s
|
||||
nc.delete_stack(board_id=board.id, stack_id=s.id)
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def card(nc, board, stack):
|
||||
c = nc.create_card(board_id=board.id, stack_id=stack.id, title="test card fixture")
|
||||
|
@ -82,7 +88,7 @@ def test_create_card(nc: NextCloudDeckAPI, board, stack):
|
|||
|
||||
def test_create_label(board: Board, nc: NextCloudDeckAPI, stack: Stack, card: Card):
|
||||
label = nc.create_label(board_id=board.id, title="Test label")
|
||||
labels = nc.get_labels(board_id=board.id)
|
||||
labels = nc.get_board_labels(board_id=board.id)
|
||||
for l in labels:
|
||||
if l.id == label.id:
|
||||
assert l == label
|
||||
|
@ -113,6 +119,18 @@ def test_create_label(board: Board, nc: NextCloudDeckAPI, stack: Stack, card: Ca
|
|||
|
||||
def test_get_cards_from_stack(board, stack, card, nc: NextCloudDeckAPI):
|
||||
cards = nc.get_cards_from_stack(board_id=board.id, stack_id=stack.id)
|
||||
|
||||
assert len(cards) == 1
|
||||
assert cards[0] == card
|
||||
|
||||
|
||||
def test_reorder_card(board, stack, stack2, card, nc: NextCloudDeckAPI):
|
||||
assert card.stack_id == stack.id
|
||||
nc.reorder_card(board.id, stack.id, card.id, card.order - 1, stack2.id)
|
||||
cards1 = nc.get_cards_from_stack(board.id, stack.id)
|
||||
cards2 = nc.get_cards_from_stack(board.id, stack2.id)
|
||||
assert len(cards1) == 0
|
||||
assert len(cards2) == 1
|
||||
card_moved = nc.get_card(board.id, stack2.id, card.id)
|
||||
assert card.title == card_moved.title
|
||||
assert card.stack_id != card_moved.stack_id
|
||||
assert card_moved.stack_id == stack2.id
|
9
tox.ini
9
tox.ini
|
@ -1,6 +1,7 @@
|
|||
# For more information about tox, see https://tox.readthedocs.io/en/latest/
|
||||
[tox]
|
||||
envlist = py37,py38,py39,flake8
|
||||
envlist = py38,py39,flake8
|
||||
isolated_build = True
|
||||
|
||||
[testenv]
|
||||
;changedir=tests
|
||||
|
@ -16,7 +17,7 @@ deps = flake8
|
|||
commands = flake8
|
||||
|
||||
[flake8]
|
||||
ignore = F401
|
||||
ignore = F401,E501,W605
|
||||
exclude =
|
||||
.git,
|
||||
__pycache__,
|
||||
|
@ -28,4 +29,6 @@ exclude =
|
|||
.pytest_cache,
|
||||
.tox,
|
||||
*.pyc,
|
||||
*.egg
|
||||
*.egg,
|
||||
venv,
|
||||
test
|
||||
|
|
Ładowanie…
Reference in New Issue