Skip to content

Commit

Permalink
Update the way we store the multiple TOS languages
Browse files Browse the repository at this point in the history
  • Loading branch information
martinRenou committed Jul 27, 2022
1 parent 245dd27 commit 2ae496d
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 100 deletions.
73 changes: 45 additions & 28 deletions plugins/quetz_tos/quetz_tos/api.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import os
import uuid
from tempfile import SpooledTemporaryFile
from typing import List

from fastapi import APIRouter, Depends, File, HTTPException, UploadFile, status
from fastapi import APIRouter, Depends, File, HTTPException, UploadFile, status, Query
from sqlalchemy.orm.session import Session

from quetz import authorization, dao
from quetz.config import Config
from quetz.deps import get_dao, get_db, get_rules

from .db_models import TermsOfService, TermsOfServiceSignatures
from .db_models import TermsOfServiceFile, TermsOfService, TermsOfServiceSignatures

router = APIRouter()
config = Config()
Expand All @@ -34,34 +35,37 @@ def post_file(file):


@router.get("/api/tos", tags=['Terms of Service'])
def get_current_tos(lang: str = "EN", db: Session = Depends(get_db)):

terms_of_services = (
db.query(TermsOfService).order_by(TermsOfService.time_created.desc()).all()
def get_current_tos(db: Session = Depends(get_db)):
current_tos = (
db.query(TermsOfService).order_by(TermsOfService.time_created.desc()).first()
)
current_tos = None
for tos in terms_of_services:
if tos.language == lang:
current_tos = tos
break

if current_tos:
f = pkgstore.serve_path("root", current_tos.filename)
data_bytes = f.read()
return {
"id": str(uuid.UUID(bytes=current_tos.id)),
"content": data_bytes.decode('utf-8'),
"uploader_id": str(uuid.UUID(bytes=current_tos.uploader_id)),
"filename": current_tos.filename,
"language": current_tos.language,
"time_created": current_tos.time_created,
}
else:
if current_tos is None:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="terms of service file not found",
detail=f"terms of service not found",
)

tos_files = []
for tos_file in current_tos.files:
f = pkgstore.serve_path("root", tos_file.filename)
data_bytes = f.read()

tos_files.append(
{
"content": data_bytes.decode('utf-8'),
"filename": tos_file.filename,
"language": tos_file.language,
}
)

return {
"id": str(uuid.UUID(bytes=current_tos.id)),
"uploader_id": str(uuid.UUID(bytes=current_tos.uploader_id)),
"files": tos_files,
"time_created": current_tos.time_created,
}


@router.get("/api/tos/status", status_code=201, tags=['Terms of Service'])
def get_current_tos_status(
Expand Down Expand Up @@ -162,15 +166,28 @@ def sign_current_tos(

@router.post("/api/tos/upload", status_code=201, tags=['Terms of Service'])
def upload_tos(
lang: str = "EN",
lang: List[str] = Query(...),
db: Session = Depends(get_db),
auth: authorization.Rules = Depends(get_rules),
tos_file: UploadFile = File(...),
tos_files: List[UploadFile] = File(...),
):
user_id = auth.assert_server_roles(
["owner"], "To upload new Terms of Services you need to be a server owner."
)
filename = post_file(tos_file)
tos = TermsOfService(uploader_id=user_id, filename=filename, language=lang)

if len(lang) != len(tos_files):
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=f"Number of languages '{lang}' does not match the number of uploaded files",
)

filenames = [post_file(tos_file) for tos_file in tos_files]

tos_files = [
TermsOfServiceFile(filename=filename, language=language)
for filename, language in zip(filenames, lang)
]
tos = TermsOfService(uploader_id=user_id, files=tos_files)

db.add(tos)
db.commit()
12 changes: 10 additions & 2 deletions plugins/quetz_tos/quetz_tos/db_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,21 @@
from quetz.db_models import UUID, Base


class TermsOfServiceFile(Base):
__tablename__ = 'quetz_tos_file'

id = Column(UUID, primary_key=True, default=lambda: uuid.uuid4().bytes)
filename = Column(String)
language = Column(String)
tos_id = Column(UUID, ForeignKey("quetz_tos.id"), primary_key=True)


class TermsOfService(Base):
__tablename__ = 'quetz_tos'

id = Column(UUID, primary_key=True, default=lambda: uuid.uuid4().bytes)
uploader_id = Column(UUID)
filename = Column(String)
language = Column(String)
files = relationship("TermsOfServiceFile")
time_created = Column(DateTime, nullable=False, server_default=func.now())


Expand Down
34 changes: 14 additions & 20 deletions plugins/quetz_tos/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,38 +28,32 @@ def member_user(db):

@fixture
def tos(db, owner_user):
tos = db_models.TermsOfService(
uploader_id=owner_user.id, filename="tos_en.txt", language="EN"
)
tos_en = db_models.TermsOfServiceFile(filename="tos_en.txt", language="EN")
tos_fr = db_models.TermsOfServiceFile(filename="tos_fr.txt", language="FR")

tos2 = db_models.TermsOfService(
uploader_id=owner_user.id, filename="tos_fr.txt", language="FR"
)
tos = db_models.TermsOfService(uploader_id=owner_user.id, files=[tos_en, tos_fr])

db.add(tos)
db.add(tos2)
db.commit()

yield [tos, tos2]
yield tos


@fixture
def tos_file(config):
pkgstore = config.get_package_store()
pkgstore.add_file(b"demo tos", "root", "tos_en.txt")
pkgstore.add_file(b"demo tos", "root", "tos_fr.txt")
pkgstore.add_file(b"demo tos en", "root", "tos_en.txt")
pkgstore.add_file(b"demo tos fr", "root", "tos_fr.txt")


@fixture
def tos_sign(db, tos, member_user):
all_signed_tos = []
for a_tos in tos:
tos_sign = db_models.TermsOfServiceSignatures(
tos_id=a_tos.id,
user_id=member_user.id,
)

db.add(tos_sign)
all_signed_tos.append(tos_sign)
tos_sign = db_models.TermsOfServiceSignatures(
tos_id=tos.id,
user_id=member_user.id,
)

db.add(tos_sign)
db.commit()
yield all_signed_tos

yield tos_sign
68 changes: 18 additions & 50 deletions plugins/quetz_tos/tests/test_quetz_tos.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,79 +9,48 @@ def plugins():
return ["quetz-tos"]


def upload_tos_en(client):
tos_en_filename = "tos_en.txt"
tos_en_content = "demo tos"
url = "/api/tos/upload?lang=EN"
def upload_tos(client):
url = "/api/tos/upload?lang=EN&lang=FR"

files_to_upload = {'tos_file': (tos_en_filename, io.StringIO(tos_en_content))}

response = client.post(url, files=files_to_upload)
return response


def upload_tos_fr(client):
tos_fr_filename = "tos_fr.txt"
tos_fr_content = "demo tos"
url = "/api/tos/upload?lang=FR"

files_to_upload = {'tos_file': (tos_fr_filename, io.StringIO(tos_fr_content))}
files_to_upload = (
('tos_files', ("tos_en.txt", io.StringIO("demo tos en"))),
('tos_files', ("tos_fr.txt", io.StringIO("demo tos fr"))),
)

response = client.post(url, files=files_to_upload)
return response


def test_tos_en_upload_by_member(client, member_user):
response = client.get("/api/dummylogin/alice")
assert response.status_code == 200

response = upload_tos_en(client)
assert response.status_code == 403
assert response.json()['detail'] == [
'To upload new Terms of Services you need to be a server owner.'
]


def test_tos_fr_upload_by_member(client, member_user):
def test_tos_upload_by_member(client, member_user):
response = client.get("/api/dummylogin/alice")
assert response.status_code == 200

response = upload_tos_fr(client)
response = upload_tos(client)
assert response.status_code == 403
assert response.json()['detail'] == [
'To upload new Terms of Services you need to be a server owner.'
]


def test_tos_en_upload_by_owner(client, owner_user):
response = client.get("/api/dummylogin/madhurt")
assert response.status_code == 200

response = upload_tos_en(client)
assert response.status_code == 201
assert response.content == b'null'


def test_tos_fr_upload_by_owner(client, owner_user):
def test_tos_upload_by_owner(client, owner_user):
response = client.get("/api/dummylogin/madhurt")
assert response.status_code == 200

response = upload_tos_fr(client)
response = upload_tos(client)
assert response.status_code == 201
assert response.content == b'null'


def test_get_tos_en(client, tos_file, tos):
response = client.get('/api/tos?lang=EN')
assert response.json()['filename'] == 'tos_en.txt'
assert response.json()['content'] == 'demo tos'

def test_get_tos(client, tos_file, tos):
response = client.get('/api/tos')

def test_get_tos_fr(client, tos_file, tos):
response = client.get('/api/tos?lang=FR')
assert response.json()['files'][0]['language'] == 'EN'
assert response.json()['files'][0]['filename'] == 'tos_en.txt'
assert response.json()['files'][0]['content'] == 'demo tos en'

assert response.json()['filename'] == 'tos_fr.txt'
assert response.json()['content'] == 'demo tos'
assert response.json()['files'][1]['language'] == 'FR'
assert response.json()['files'][1]['filename'] == 'tos_fr.txt'
assert response.json()['files'][1]['content'] == 'demo tos fr'


def test_tos_sign(client, member_user, tos_file, tos):
Expand Down Expand Up @@ -133,7 +102,6 @@ def test_check_additional_permissions_hook_with_member(
def test_check_additional_permissions_hook_with_member_signed(
db, client, member_user, tos, tos_file, tos_sign
):
print(f"################################ member::: <{member_user}>")
response = client.get("/api/dummylogin/alice")
assert response.status_code == 200

Expand Down

0 comments on commit 2ae496d

Please sign in to comment.