refactor(endpoints/api/repoemail): added in pre_oci model
### Description of Changes this is so we can abstract away the data interface [TESTING->locally with docker compose] Issue: https://coreosdev.atlassian.net/browse/QUAY-626 ## Reviewer Checklist - [ ] It works! - [ ] Comments provide sufficient explanations for the next contributor - [ ] Tests cover changes and corner cases - [ ] Follows Quay syntax patterns and format
This commit is contained in:
parent
82488c9102
commit
d01b55f27d
5 changed files with 158 additions and 16 deletions
|
@ -7,9 +7,9 @@ from flask import request, abort
|
||||||
from endpoints.api import (resource, nickname, require_repo_admin, RepositoryParamResource,
|
from endpoints.api import (resource, nickname, require_repo_admin, RepositoryParamResource,
|
||||||
log_action, validate_json_request, internal_only,
|
log_action, validate_json_request, internal_only,
|
||||||
path_param, show_if)
|
path_param, show_if)
|
||||||
|
from endpoints.api.repoemail_models_pre_oci import pre_oci_model as model
|
||||||
from endpoints.exception import NotFound
|
from endpoints.exception import NotFound
|
||||||
from app import tf
|
from app import tf
|
||||||
from data import model
|
|
||||||
from data.database import db
|
from data.database import db
|
||||||
from util.useremails import send_repo_authorization_email
|
from util.useremails import send_repo_authorization_email
|
||||||
|
|
||||||
|
@ -19,15 +19,6 @@ import features
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def record_view(record):
|
|
||||||
return {
|
|
||||||
'email': record.email,
|
|
||||||
'repository': record.repository.name,
|
|
||||||
'namespace': record.repository.namespace_user.username,
|
|
||||||
'confirmed': record.confirmed
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@internal_only
|
@internal_only
|
||||||
@resource('/v1/repository/<apirepopath:repository>/authorizedemail/<email>')
|
@resource('/v1/repository/<apirepopath:repository>/authorizedemail/<email>')
|
||||||
@show_if(features.MAILING)
|
@show_if(features.MAILING)
|
||||||
|
@ -39,11 +30,11 @@ class RepositoryAuthorizedEmail(RepositoryParamResource):
|
||||||
@nickname('checkRepoEmailAuthorized')
|
@nickname('checkRepoEmailAuthorized')
|
||||||
def get(self, namespace, repository, email):
|
def get(self, namespace, repository, email):
|
||||||
""" Checks to see if the given e-mail address is authorized on this repository. """
|
""" Checks to see if the given e-mail address is authorized on this repository. """
|
||||||
record = model.repository.get_email_authorized_for_repo(namespace, repository, email)
|
record = model.get_email_authorized_for_repo(namespace, repository, email)
|
||||||
if not record:
|
if not record:
|
||||||
abort(404)
|
abort(404)
|
||||||
|
|
||||||
return record_view(record)
|
return record.to_dict()
|
||||||
|
|
||||||
|
|
||||||
@require_repo_admin
|
@require_repo_admin
|
||||||
|
@ -52,12 +43,12 @@ class RepositoryAuthorizedEmail(RepositoryParamResource):
|
||||||
""" Starts the authorization process for an e-mail address on a repository. """
|
""" Starts the authorization process for an e-mail address on a repository. """
|
||||||
|
|
||||||
with tf(db):
|
with tf(db):
|
||||||
record = model.repository.get_email_authorized_for_repo(namespace, repository, email)
|
record = model.get_email_authorized_for_repo(namespace, repository, email)
|
||||||
if record and record.confirmed:
|
if record and record.confirmed:
|
||||||
return record_view(record)
|
return record.to_dict()
|
||||||
|
|
||||||
if not record:
|
if not record:
|
||||||
record = model.repository.create_email_authorization_for_repo(namespace, repository, email)
|
record = model.create_email_authorization_for_repo(namespace, repository, email)
|
||||||
|
|
||||||
send_repo_authorization_email(namespace, repository, email, record.code)
|
send_repo_authorization_email(namespace, repository, email, record.code)
|
||||||
return record_view(record)
|
return record.to_dict()
|
||||||
|
|
44
endpoints/api/repoemail_models_interface.py
Normal file
44
endpoints/api/repoemail_models_interface.py
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
from abc import ABCMeta, abstractmethod
|
||||||
|
from collections import namedtuple
|
||||||
|
|
||||||
|
from six import add_metaclass
|
||||||
|
|
||||||
|
|
||||||
|
class RepositoryAuthorizedEmail(
|
||||||
|
namedtuple('RepositoryAuthorizedEmail', ['email', 'repository_name', 'namespace_name', 'confirmed', 'code',])):
|
||||||
|
"""
|
||||||
|
Tag represents a name to an image.
|
||||||
|
:type email: string
|
||||||
|
:type repository_name: string
|
||||||
|
:type namespace_name: string
|
||||||
|
:type confirmed: boolean
|
||||||
|
:type code: string
|
||||||
|
"""
|
||||||
|
|
||||||
|
def to_dict(self):
|
||||||
|
return {
|
||||||
|
'email': self.email,
|
||||||
|
'repository': self.repository_name,
|
||||||
|
'namespace': self.namespace_name,
|
||||||
|
'confirmed': self.confirmed,
|
||||||
|
'code': self.code
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@add_metaclass(ABCMeta)
|
||||||
|
class RepoEmailDataInterface(object):
|
||||||
|
"""
|
||||||
|
Interface that represents all data store interactions required by a Repo Email.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def get_email_authorized_for_repo(self, namespace_name, repository_name, email):
|
||||||
|
"""
|
||||||
|
Returns a RepositoryAuthorizedEmail if available else None
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def create_email_authorization_for_repo(self, namespace_name, repository_name, email):
|
||||||
|
"""
|
||||||
|
Returns the newly created repository authorized email.
|
||||||
|
"""
|
26
endpoints/api/repoemail_models_pre_oci.py
Normal file
26
endpoints/api/repoemail_models_pre_oci.py
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
from data import model
|
||||||
|
from endpoints.api.repoemail_models_interface import RepoEmailDataInterface, RepositoryAuthorizedEmail
|
||||||
|
|
||||||
|
|
||||||
|
def _return_none_or_data(func, namespace_name, repository_name, email):
|
||||||
|
data = func(namespace_name, repository_name, email)
|
||||||
|
if data is None:
|
||||||
|
return data
|
||||||
|
return RepositoryAuthorizedEmail(email, repository_name, namespace_name, data.confirmed, data.code)
|
||||||
|
|
||||||
|
|
||||||
|
class PreOCIModel(RepoEmailDataInterface):
|
||||||
|
"""
|
||||||
|
PreOCIModel implements the data model for the Repo Email using a database schema
|
||||||
|
before it was changed to support the OCI specification.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def get_email_authorized_for_repo(self, namespace_name, repository_name, email):
|
||||||
|
return _return_none_or_data(model.repository.get_email_authorized_for_repo, namespace_name, repository_name, email)
|
||||||
|
|
||||||
|
def create_email_authorization_for_repo(self, namespace_name, repository_name, email):
|
||||||
|
return _return_none_or_data(model.repository.create_email_authorization_for_repo, namespace_name, repository_name,
|
||||||
|
email)
|
||||||
|
|
||||||
|
|
||||||
|
pre_oci_model = PreOCIModel()
|
81
endpoints/api/test/test_repoemail_models_pre_oci.py
Normal file
81
endpoints/api/test/test_repoemail_models_pre_oci.py
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
import pytest
|
||||||
|
from mock import Mock
|
||||||
|
|
||||||
|
import util
|
||||||
|
from data import model
|
||||||
|
from endpoints.api.repoemail_models_interface import RepositoryAuthorizedEmail
|
||||||
|
from endpoints.api.repoemail_models_pre_oci import pre_oci_model
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def get_monkeypatch(monkeypatch):
|
||||||
|
return monkeypatch
|
||||||
|
|
||||||
|
|
||||||
|
def return_none(name, repo, email):
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def get_return_mock(mock):
|
||||||
|
def return_mock(name, repo, email):
|
||||||
|
return mock
|
||||||
|
|
||||||
|
return return_mock
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_email_authorized_for_repo(get_monkeypatch):
|
||||||
|
mock = Mock()
|
||||||
|
|
||||||
|
get_monkeypatch.setattr(model.repository, 'get_email_authorized_for_repo', mock)
|
||||||
|
|
||||||
|
pre_oci_model.get_email_authorized_for_repo('namespace_name', 'repository_name', 'email')
|
||||||
|
|
||||||
|
mock.assert_called_once_with('namespace_name', 'repository_name', 'email')
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_email_authorized_for_repo_return_none(get_monkeypatch):
|
||||||
|
get_monkeypatch.setattr(model.repository, 'get_email_authorized_for_repo', return_none)
|
||||||
|
|
||||||
|
repo = pre_oci_model.get_email_authorized_for_repo('namespace_name', 'repository_name', 'email')
|
||||||
|
|
||||||
|
assert repo is None
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_email_authorized_for_repo_return_repo(get_monkeypatch):
|
||||||
|
mock = Mock(confirmed=True, code='code')
|
||||||
|
get_monkeypatch.setattr(model.repository, 'get_email_authorized_for_repo', get_return_mock(mock))
|
||||||
|
|
||||||
|
actual = pre_oci_model.get_email_authorized_for_repo('namespace_name', 'repository_name', 'email')
|
||||||
|
|
||||||
|
assert actual == RepositoryAuthorizedEmail('email', 'repository_name', 'namespace_name', True, 'code')
|
||||||
|
|
||||||
|
|
||||||
|
def test_create_email_authorization_for_repo(get_monkeypatch):
|
||||||
|
mock = Mock()
|
||||||
|
get_monkeypatch.setattr(model.repository, 'create_email_authorization_for_repo', mock)
|
||||||
|
|
||||||
|
pre_oci_model.create_email_authorization_for_repo('namespace_name', 'repository_name', 'email')
|
||||||
|
|
||||||
|
mock.assert_called_once_with('namespace_name', 'repository_name', 'email')
|
||||||
|
|
||||||
|
|
||||||
|
def test_create_email_authorization_for_repo_return_none(get_monkeypatch):
|
||||||
|
get_monkeypatch.setattr(model.repository, 'create_email_authorization_for_repo', return_none)
|
||||||
|
|
||||||
|
assert pre_oci_model.create_email_authorization_for_repo('namespace_name', 'repository_name', 'email') is None
|
||||||
|
|
||||||
|
|
||||||
|
def test_create_email_authorization_for_repo_return_mock(get_monkeypatch):
|
||||||
|
mock = Mock()
|
||||||
|
get_monkeypatch.setattr(model.repository, 'create_email_authorization_for_repo', get_return_mock(mock))
|
||||||
|
|
||||||
|
assert pre_oci_model.create_email_authorization_for_repo('namespace_name', 'repository_name', 'email') is not None
|
||||||
|
|
||||||
|
|
||||||
|
def test_create_email_authorization_for_repo_return_value(get_monkeypatch):
|
||||||
|
mock = Mock(confirmed=False, code='code')
|
||||||
|
|
||||||
|
get_monkeypatch.setattr(model.repository, 'create_email_authorization_for_repo', get_return_mock(mock))
|
||||||
|
|
||||||
|
actual = pre_oci_model.create_email_authorization_for_repo('namespace_name', 'repository_name', 'email')
|
||||||
|
assert actual == RepositoryAuthorizedEmail('email', 'repository_name', 'namespace_name', False, 'code')
|
Reference in a new issue