parent
8276bb4b29
commit
a21db9ccf3
@ -0,0 +1,43 @@ |
||||
"""Added the 'author' table. |
||||
|
||||
Revision ID: 1ee62841eb90 |
||||
Revises: 4594e1b85c8b |
||||
Create Date: 2019-12-11 07:25:38.054776 |
||||
|
||||
""" |
||||
from alembic import op |
||||
import sqlalchemy as sa |
||||
|
||||
|
||||
# revision identifiers, used by Alembic. |
||||
revision = '1ee62841eb90' |
||||
down_revision = '4594e1b85c8b' |
||||
branch_labels = None |
||||
depends_on = None |
||||
|
||||
|
||||
def upgrade(): |
||||
# ### commands auto generated by Alembic - please adjust! ### |
||||
op.create_table('author', |
||||
sa.Column('author_id', sa.Integer(), nullable=False), |
||||
sa.Column('author_name', sa.String(length=100), nullable=False), |
||||
sa.PrimaryKeyConstraint('author_id'), |
||||
sa.UniqueConstraint('author_name') |
||||
) |
||||
op.create_table('article_author', |
||||
sa.Column('article_author_id', sa.Integer(), nullable=False), |
||||
sa.Column('seq_no', sa.Integer(), nullable=False), |
||||
sa.Column('article_id', sa.Integer(), nullable=False), |
||||
sa.Column('author_id', sa.Integer(), nullable=False), |
||||
sa.ForeignKeyConstraint(['article_id'], ['article.article_id'], ondelete='CASCADE'), |
||||
sa.ForeignKeyConstraint(['author_id'], ['author.author_id'], ondelete='CASCADE'), |
||||
sa.PrimaryKeyConstraint('article_author_id'), |
||||
) |
||||
# ### end Alembic commands ### |
||||
|
||||
|
||||
def downgrade(): |
||||
# ### commands auto generated by Alembic - please adjust! ### |
||||
op.drop_table('article_author') |
||||
op.drop_table('author') |
||||
# ### end Alembic commands ### |
@ -0,0 +1,29 @@ |
||||
""" Handle author requests. """ |
||||
|
||||
from flask import jsonify |
||||
|
||||
from asl_articles import app |
||||
from asl_articles.models import Author |
||||
|
||||
# --------------------------------------------------------------------- |
||||
|
||||
@app.route( "/authors" ) |
||||
def get_authors(): |
||||
"""Get all authors.""" |
||||
return jsonify( do_get_authors() ) |
||||
|
||||
def do_get_authors(): |
||||
"""Get all authors.""" |
||||
|
||||
# get all the authors |
||||
return { |
||||
r.author_id: _get_author_vals(r) |
||||
for r in Author.query #pylint: disable=not-an-iterable |
||||
} |
||||
|
||||
def _get_author_vals( author ): |
||||
"""Extract public fields from an Author record.""" |
||||
return { |
||||
"author_id": author.author_id, |
||||
"author_name": author.author_name |
||||
} |
@ -0,0 +1,83 @@ |
||||
""" Test author operations. """ |
||||
|
||||
import urllib.request |
||||
import json |
||||
|
||||
from asl_articles.tests.utils import init_tests, find_child, wait_for_elem, find_search_result |
||||
from asl_articles.tests.react_select import ReactSelect |
||||
|
||||
from asl_articles.tests.test_articles import _create_article, _edit_article |
||||
|
||||
# --------------------------------------------------------------------- |
||||
|
||||
def test_authors( webdriver, flask_app, dbconn ): |
||||
"""Test author operations.""" |
||||
|
||||
# initialize |
||||
init_tests( webdriver, flask_app, dbconn ) |
||||
|
||||
# create some test articles |
||||
_create_article( { "title": "article 1" } ) |
||||
_create_article( { "title": "article 2" } ) |
||||
all_authors = set() |
||||
_check_authors( flask_app, all_authors, [ [], [] ] ) |
||||
|
||||
# add an author to article #1 |
||||
_edit_article( find_search_result( "article 1" ), { |
||||
"authors": [ "+andrew" ] |
||||
} ) |
||||
_check_authors( flask_app, all_authors, [ ["andrew"], [] ] ) |
||||
|
||||
# add authors to article #2 |
||||
_edit_article( find_search_result( "article 2" ), { |
||||
"authors": [ "+bob", "+charlie" ] |
||||
} ) |
||||
_check_authors( flask_app, all_authors, [ ["andrew"], ["bob","charlie"] ] ) |
||||
|
||||
# add/remove authors to article #2 |
||||
_edit_article( find_search_result( "article 2" ), { |
||||
"authors": [ "+dan", "-charlie", "+andrew" ] |
||||
} ) |
||||
_check_authors( flask_app, all_authors, [ ["andrew"], ["bob","dan","andrew"] ] ) |
||||
|
||||
# add new/existing authors to article #1 |
||||
# NOTE: The main thing we're checking here is that despite new and existing authors |
||||
# being added to the article, their order is preserved. |
||||
_edit_article( find_search_result( "article 1" ), { |
||||
"authors": [ "+bob", "+new1", "+charlie", "+new2" ] |
||||
} ) |
||||
_check_authors( flask_app, all_authors, [ |
||||
["andrew","bob","new1","charlie","new2"], ["bob","dan","andrew"] |
||||
] ) |
||||
|
||||
# --------------------------------------------------------------------- |
||||
|
||||
def _check_authors( flask_app, all_authors, expected ): |
||||
"""Check the authors of the test articles.""" |
||||
|
||||
# update the complete list of authors |
||||
# NOTE: Unlike tags, authors remain in the database even if no-one is referencing them, |
||||
# so we need to track them over the life of the entire series of tests. |
||||
for authors in expected: |
||||
all_authors.update( authors ) |
||||
|
||||
# check the authors in the UI |
||||
for article_no,authors in enumerate( expected ): |
||||
|
||||
# check the authors for the next article |
||||
sr = find_search_result( "article {}".format( 1+article_no ) ) |
||||
find_child( ".edit", sr ).click() |
||||
dlg = wait_for_elem( 2, "#modal-form" ) |
||||
select = ReactSelect( find_child( ".authors .react-select", dlg ) ) |
||||
assert select.get_multiselect_values() == authors |
||||
|
||||
# check that the list of available authors is correct |
||||
assert select.get_multiselect_choices() == sorted( all_authors.difference( authors ) ) |
||||
|
||||
# close the dialog |
||||
find_child( "button.cancel", dlg ).click() |
||||
|
||||
# check the authors in the database |
||||
url = flask_app.url_for( "get_authors" ) |
||||
authors = json.load( urllib.request.urlopen( url ) ) |
||||
assert set( a["author_name"] for a in authors.values() ) == all_authors |
Loading…
Reference in new issue