Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions learning_journal/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@ def includeme(config):
config.add_route("update", "/journal/{id:\d+}/edit-entry")
config.add_route("login", "/login")
config.add_route("logout", "/logout")
config.add_route("delete", "/delete/{id:\d+}")
config.add_route("tweet", "/tweet/{id:\d+}")
25 changes: 25 additions & 0 deletions learning_journal/static/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
$(document).ready(function(){
$("#homeSubmitButton").on("click", function(e){
e.preventDefault()
entry = $(this).parent().serializeArray()
$.ajax({
method: 'POST',
url: '/journal/new-entry',
data: {
"csrf_token": entry[0]["value"],
"title": entry[1]["value"],
"body": entry[2]["value"]
},
success: function(result){
new_id = parseInt($(".entryListItem a").first().attr('href').split('/')[4]) + 1
$(".entryListItem").first().prepend(
"<li class='entryListItem'>" +
"<h3><a href=\"journal/" + new_id + "\">" + entry[1]["value"] + "</a></h3>" +
"<p class='date'>Created " + Date.now() + " </p>" +
"<hr />" +
"</li>"
)
}
});
});
});
Binary file added learning_journal/static/assets/awesome.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions learning_journal/static/base.css
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,8 @@ h2{
h3{
font-size:1.25em;
}

body, main{
margin: 0px;
width: 100%;
}
19 changes: 18 additions & 1 deletion learning_journal/static/layout.css
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,28 @@ header a{
font-family: Share Tech Mono;
color: white;
line-height: 40px;
padding-left: 8px;
margin-left: 12px;
}

header a:hover {
border-bottom: 2px solid white;
}

main {
width: 90%;
height: 100%;
margin: auto;
}

.entryEditList li{
display: inline;
margin-left: 12px;
}

.entryEditList a{
color: black;
}

.entryEditList a:hover{
border-bottom: 2px solid black;
}
13 changes: 13 additions & 0 deletions learning_journal/static/module.css
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@
background-color: lightgrey;
}

#entryListWrapper ul{
list-style: none;
margin: 0px;
padding-left: 2px;
}

#entryDisplayWrapper{
width: 80%;
margin: auto;
Expand Down Expand Up @@ -69,4 +75,11 @@ form #submitButton{

#pageTitle{
text-align: center;
}

header img {
float: right;
height: 100px;
width: 100px;
padding-right: 10px;
}
48 changes: 0 additions & 48 deletions learning_journal/static/reset.css

This file was deleted.

9 changes: 7 additions & 2 deletions learning_journal/templates/entry.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,14 @@
<p id="author">by Ted Callahan</p>
</div>
<div id=#entryWrapper>
{{ entry.body|e }}
{{ entry.body|safe }}
</div>
{% if request.authenticated_userid %}
<a href="{{ request.route_url('update', id=entry.id) }}">EDIT</a>
<ul class="entryEditList">
<li><a href="{{ request.route_url('update', id=entry.id) }}"><i class="fa fa-pencil-square-o" aria-hidden="true"></i> EDIT</a></li>
<li><a href="{{ request.route_url('delete', id=entry.id) }}"><i class="fa fa-trash-o" aria-hidden="true"></i> DELETE</a></li>
<li><a href="{{ request.route_url('tweet', id=entry.id) }}"><i class="fa fa-twitter" aria-hidden="true"></i> TWEET</a></li>
</ul>
{% endif %}
</div>
{% endblock %}
1 change: 1 addition & 0 deletions learning_journal/templates/form.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
</head>
<body>
<form method="POST">
<input type="hidden" name="csrf_token" value="{{ request.session.get_csrf_token() }}" />
<p>
<label for="name">Name</label>
<input type="text" name="name" />
Expand Down
8 changes: 7 additions & 1 deletion learning_journal/templates/layout.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@
<meta charset-"UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href='https://fonts.googleapis.com/css?family=Share+Tech+Mono' rel='stylesheet' type='text/css'>
<link rel="stylesheet" href="{{ request.static_path('learning_journal:static/reset.css') }}">
<link rel="stylesheet" href="{{ request.static_path('learning_journal:static/base.css') }}">
<link rel="stylesheet" href="{{ request.static_path('learning_journal:static/layout.css') }}">
<link rel="stylesheet" href="{{ request.static_path('learning_journal:static/module.css') }}">

</head>
<body>
<header>
Expand All @@ -20,9 +20,15 @@
{% else %}
<a href="{{ request.route_url('login') }}">Login</a>
{% endif %}
<img class="headerPic" src="{{ request.static_path('learning_journal:static/assets/awesome.png') }}" alt="awesome">
</header>
<main>
{% block body %}{% endblock %}
</main>
<script src="https://code.jquery.com/jquery-3.1.1.min.js"
integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8="
crossorigin="anonymous"></script>
<script src="https://use.fontawesome.com/927692b4ce.js"></script>
<script src="{{ request.static_path('learning_journal:static/app.js') }}"></script>
</body>
</html>
10 changes: 10 additions & 0 deletions learning_journal/templates/list.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,16 @@
{% else %}
<p>This Journal is Empty. =(</p>
{% endif %}
{% if request.authenticated_userid %}
<form action = '' method="POST">
<input type="hidden" name="csrf_token" value="{{ request.session.get_csrf_token() }}" />
<h3>Title:</h3>
<input type="text" name="title" id="entryTitle" placeholder="Enter Title Here...">
<h3>Body:</h3>
<textarea id="entryBody" name="body" placeholder="Enter Body Here...""></textarea>
<input type="submit" id="homeSubmitButton">
</form>
{% endif %}
</ul>
</div>
{% endblock %}
1 change: 0 additions & 1 deletion learning_journal/templates/login.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
{% block body %}
<h2>Login</h2>
<form action="" method="POST">
<input type="hidden" name="csrf_token" value="{{ request.session.get_csrf_token() }}" />
<div class="field">
<label for="username">Username</label>
<input type="text" name="username" id="username"/>
Expand Down
8 changes: 0 additions & 8 deletions learning_journal/templates/mytemplate.jinja2

This file was deleted.

78 changes: 57 additions & 21 deletions learning_journal/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,18 @@ def add_models(dummy_request):
]


@pytest.fixture
def set_auth_credentials():
"""Make a username/password combo for testing."""
import os
from passlib.apps import custom_app_context as pwd_context

os.environ["AUTH_USERNAME"] = "testme"
os.environ["AUTH_PASSWORD"] = pwd_context.hash("foobar")

# ======== UNIT TESTS ==========


def test_new_entries_are_added(db_session):
"""New expenses get added to the database."""
for entry in ENTRIES:
Expand Down Expand Up @@ -127,14 +137,14 @@ def test_create_view_updates_db_on_post(db_session, dummy_request):

query = db_session.query(Entries).all()
assert query[0].title == "Some Title."
assert query[0].body == "Some Body."
assert query[0].body[3:-4] == "Some Body."


# ======== FUNCTIONAL TESTS ===========


@pytest.fixture
def testapp():
@pytest.fixture(scope="session")
def testapp(request):
"""Create an instance of webtests TestApp for testing routes.

With the alchemy scaffold we need to add to our test application the
Expand All @@ -157,6 +167,7 @@ def main(global_config, **settings):
config.include('pyramid_jinja2')
config.include('.models')
config.include('.routes')
config.include('.security')
config.scan()
return config.make_wsgi_app()

Expand All @@ -167,14 +178,19 @@ def main(global_config, **settings):
engine = SessionFactory().bind
Base.metadata.create_all(bind=engine)

with transaction.manager:
dbsession = get_tm_session(SessionFactory, transaction.manager)
dbsession.query(Entries).delete()
def tear_down():
Base.metadata.drop_all(bind=engine)

request.addfinalizer(tear_down)

# with transaction.manager:
# dbsession = get_tm_session(SessionFactory, transaction.manager)
# dbsession.query(Entries).delete()

return testapp


@pytest.fixture
@pytest.fixture(scope="session")
def fill_the_db(testapp):
"""Fill the database with some model instances.

Expand All @@ -189,6 +205,17 @@ def fill_the_db(testapp):
row = Entries(title=entry["title"], creation_date=entry["creation_date"], body=entry["body"])
dbsession.add(row)

return dbsession


@pytest.fixture
def new_session(testapp):
"""Return a session for inspecting the database."""
SessionFactory = testapp.app.registry["dbsession_factory"]
with transaction.manager:
dbsession = get_tm_session(SessionFactory, transaction.manager)
return dbsession


def test_home_route_has_list(testapp):
"""The home page has a list in the html."""
Expand All @@ -197,29 +224,25 @@ def test_home_route_has_list(testapp):
assert len(html.find_all("ul")) == 1


def test_home_route_with_data_has_filled_list(testapp, fill_the_db):
"""When there's data in the database, the home page has some rows."""
response = testapp.get('/', status=200)
html = response.html
assert len(html.find_all("li")) == 6


def test_home_route_has_list2(testapp):
"""Without data the home page only has a list."""
"""Without data the home page has an empty list."""
response = testapp.get('/', status=200)
html = response.html
assert len(html.find_all("ul")) == 1
assert len(html.find_all("li")) == 0


def test_create_entry_route_has_form(testapp):
def test_create_entry_route_forbidden(testapp):
"""Test that the "create" route loads a page with a form."""
response = testapp.get('/journal/new-entry', status=200)
html = response.html
assert len(html.find_all("form")) == 1
response = testapp.get('/journal/new-entry', status=403)
assert "Forbidden" in response.text
assert response.status_code == 403

# ================= LOGGED IN ====================


def test_create_view_post_redirects(testapp):
def test_create_view_post_redirects(set_auth_credentials, testapp):
"""Test that a post request redirects to home."""
response = testapp.post("/login", params={"username": "testme", "password": "foobar"})
post_params = {
'title': 'Some Title.',
'body': 'Some Body.'
Expand All @@ -230,6 +253,12 @@ def test_create_view_post_redirects(testapp):
assert len(full_response.html.find_all(id='entryListWrapper')) == 1


def test_entry_route_not_found(testapp):
"""Test that requesting a non-existing entry returns a 404."""
response = testapp.get('/journal/99999999', status=404)
assert response.status_code == 404


def test_create_view_adds_to_db(testapp):
"""Test that a post method to create view updates the db."""
post_params = {
Expand All @@ -241,6 +270,13 @@ def test_create_view_adds_to_db(testapp):
assert full_response.html.find(class_='entryListItem').a.text == post_params["title"]


def test_home_route_with_data_has_filled_list(testapp, fill_the_db):
"""When there's data in the database, the home page has some rows."""
response = testapp.get('/', status=200)
html = response.html
assert len(html.find_all("li")) == 6


def test_update_route_has_populated_form(testapp, fill_the_db):
"""Test the update view has a populated form."""
response = testapp.get('/journal/1/edit-entry', status=200)
Expand Down
Loading