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:
Charlton Austin 2017-07-13 15:30:07 -04:00
parent 82488c9102
commit d01b55f27d
5 changed files with 158 additions and 16 deletions

View file

@ -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()

View 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.
"""

View 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()

View 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')