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,
log_action, validate_json_request, internal_only,
path_param, show_if)
from endpoints.api.repoemail_models_pre_oci import pre_oci_model as model
from endpoints.exception import NotFound
from app import tf
from data import model
from data.database import db
from util.useremails import send_repo_authorization_email
@ -19,15 +19,6 @@ import features
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
@resource('/v1/repository/<apirepopath:repository>/authorizedemail/<email>')
@show_if(features.MAILING)
@ -39,11 +30,11 @@ class RepositoryAuthorizedEmail(RepositoryParamResource):
@nickname('checkRepoEmailAuthorized')
def get(self, namespace, repository, email):
""" 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:
abort(404)
return record_view(record)
return record.to_dict()
@require_repo_admin
@ -52,12 +43,12 @@ class RepositoryAuthorizedEmail(RepositoryParamResource):
""" Starts the authorization process for an e-mail address on a repository. """
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:
return record_view(record)
return record.to_dict()
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)
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')