Commit graph

29 commits

Author SHA1 Message Date
William Carroll
385164c6af Authorize endpoints
If I ever fully learn `servant-auth`, I'll probably recognize how naive this
hand-rolled solution is. But it works! And the code is pretty declarative, which
I like.
2020-07-30 10:23:55 +01:00
William Carroll
ca26fcd523 Debug erroneous table name
"Session" doesn't exist, but "Sessions" does.
2020-07-30 09:51:32 +01:00
William Carroll
fdd51f626c Fully support login, logout
Refactor my handlers to use the `Handler a` type instead of `IO a`; this allows
me to throwError inside of handlers that Servant properly handles. Previously I
was creating 500 errors unnecessarily.
2020-07-29 20:26:23 +01:00
William Carroll
ab12be7840 Support looking up a session by its UUID
We need to read a session from the session table using its UUID.
2020-07-29 20:21:56 +01:00
William Carroll
16f50e33bc Prefer deleting sessions by their UUID
Instead of deleting them by usernames.
2020-07-29 20:21:29 +01:00
William Carroll
c4a090e558 Support reading / writing cookies in API
Update my API type and handler types to reflect which handlers read and write
cookies.

TODO:
- Actually read from and write to Set-Cookie header
- Returning `pure NoContent` breaks my types, so I'm returning `undefined` now
2020-07-29 14:14:47 +01:00
William Carroll
cf6c8799ab Restrict users from multiple failed login attempts
I'm not resetting the failed LoginAttempt count, which is a low priority for
now, but necessary eventually.
2020-07-28 21:33:58 +01:00
William Carroll
f051b0be0b Check passwords in /login
TL;DR:
- Since POST /login is more rigorous, our accounts.csv needs to contain validly
  hashed passwords; you can use tests/create-accounts.sh to create dummy
  accounts

I still need to test the login flow and support:
- Tracking failed attempts (three maximum)
- Verifying accounts by sending emails to the users
2020-07-28 18:48:38 +01:00
William Carroll
90a521c78f Create Utils module for (|>) operator
For the past 3-4 Haskell projects on which I've worked, I've tried to habituate
the usage of the (&) operator, but I find that -- as petty as it may sound -- I
don't like the way that it looks, and I end up avoiding using it as a result.

This time around, I'm aliasing it to (|>) (i.e. Elixir style), and I'm hoping to
use it more.
2020-07-28 18:47:40 +01:00
William Carroll
36a2fea686 Create Sessions table
TL;DR:
- Create Sessions SQL schema
- Create Sessions module
- Introduce UUID dependency
2020-07-28 18:40:17 +01:00
William Carroll
012296f156 Move SQL out of API and into separate modules
Create modules for each Table in our SQL database. This cleans up the handler
bodies at the expense of introducing more files and indirection.
2020-07-28 18:38:30 +01:00
William Carroll
b355664858 Support /login
Support basic authentication.

Note the TODOs that this commit introduces to track some of the remaining work.
2020-07-28 14:15:41 +01:00
William Carroll
b170be9375 Hash passwords when creating accounts
TL;DR:
- introduce the Cryptonite library
- Remove the redundant language extensions, imports, deps from Persistent
- Prefer NoContent return type for POST /accounts
- Define custom {To,From}JSON instances for Role
2020-07-28 12:51:17 +01:00
William Carroll
bb36dd1f9e Define bespoke impls for {To,From}JSON instances
Instead of sending and receiving JSON like "accountUsername", which leaks
implementation details and is a bit unwieldy, define custom instances that
prefer the shorter, more user-friendly "username" version.
2020-07-28 11:20:15 +01:00
William Carroll
502126243d Prefer name ClearTextPassword to Password
I expect my application to have two types for passwords:
- ClearTextPassword
- CipherTextPassword
2020-07-28 11:19:47 +01:00
William Carroll
2398f1bd40 Distinguish b/w Account and User
Additionally: supporting more CRUDL methods for the Accounts and Trips tables.
2020-07-28 10:57:15 +01:00
William Carroll
6d9e76313d Partially support DELETE /trips
Allow a user to delete a trip entry from the Trips table using the Primary
Key. While this type-checks and compiles, it doesn't appear to be working as
intended. Perhaps I should use an auto-incrementing integer as the Primary
Key. I'm not sure how I want to handle this, so I'm punting for now.
2020-07-28 10:14:33 +01:00
William Carroll
0637da36cc Support GET /trips
In the spirit of support CRUDL, I added a GET /trips, which lists all of the
trips in the Trips table.
2020-07-28 10:13:38 +01:00
William Carroll
2f73d1db6c Prefer NoContent response to Bool
When I first wrote this handler I wasn't aware of the NoContent response
option.
2020-07-28 10:12:25 +01:00
William Carroll
52ac4d79bd Allow API users to create Trip entries
Next up:
- list trips
- update existing trip entries
- delete existing trip entries
2020-07-28 09:12:55 +01:00
William Carroll
475f62fb16 Prefer SQLite.Simple to Persistent
In the spirit of walking crawling before I walk, I'm preferring the less
powerful SQLite.Simple library to the more powerful (but mystifying) Persistent
library.
2020-07-27 15:22:22 +01:00
William Carroll
c38814d7a1 Add CHECK constraints to schema
I believe data should be validated at each level of the stack:
- database
- server
- client

The database, in my opinion, is the most important layer at which to validate
because you can eliminate entire classes of bugs. However, the CHECK constraint
is limited, and the more complex the predicates are, the more expensive database
operations become.

At the server and client layers, the data validations can be more sophisticated
and return more useful error messages to help users better understand the shape
of the data that our application expects.
2020-07-27 14:23:34 +01:00
William Carroll
974c63a679 Remove unnecessary language extensions
Attempting to abide by the Principle of Least Power. Also: the smaller the
headers in each module are, the happier I am.
2020-07-27 11:35:10 +01:00
William Carroll
df13b761ff Define table schema and CSVs to populate the database
TL;DR:
- Created src/init.sql, which defines the tables
- Created a data/ directory to house .csv data to populate our db
- Updated the README with usage instructions
2020-07-27 11:16:26 +01:00
William Carroll
722205b081 Remodel Account type
Remove unnecessary fields:
- name
- age

Add domain-specific fields:
- username
- password
- email
- role
2020-07-25 18:32:17 +01:00
William Carroll
d011616564 Change the name User to Account
Next I'll need to add / remove fields from the Account type.
2020-07-25 18:18:59 +01:00
William Carroll
718152ec14 Return a Session
Define the Session type and return it for the POST /user endpoint
2020-07-24 23:35:49 +01:00
William Carroll
1d47e94bbe Integrate Persistent with Servant
Query my SQLite database from within my Servant handlers. Nothing I've written
is domain-specific to the business logic yet -- I'm just making sure everything
integrates.
2020-07-24 22:48:08 +01:00
William Carroll
660b8d43e5 Support a basic API
Use Servant to create a REST API supporting the following routes:
- GET /number
- POST /other

The server interacts with a SQLite database.
2020-07-24 19:00:29 +01:00