The use of `unwrap_throw` can be used as a later grep target.
Change-Id: I8c54ed90c4289f07aecb8a1393dd10204c8bce4e
Reviewed-on: https://cl.tvl.fyi/c/depot/+/1493
Reviewed-by: glittershark <grfn@gws.fyi>
Reviewed-by: tazjin <mail@tazj.in>
Tested-by: BuildkiteCI
Fixup for CL 1492 (addcba11b0)
Additionally, add a test to verify functionality of HashSink.
Change-Id: I2a74b925a1b93ed4d3add29021d759c93e813424
Reviewed-on: https://cl.tvl.fyi/c/depot/+/1507
Tested-by: BuildkiteCI
Reviewed-by: glittershark <grfn@gws.fyi>
Toggle b/w logging in or signing up.
TL;DR:
- From my previous submission's feedback, disallow users from signing themselves
up as admins, managers; I just removed the UI element altogether, even though
the server still support this (TODO)
@dmjio says (probably correctly) that it's best to just serve the client from
the server and circumvent CORS issues altogether.
One day I will set that up. For now, this works... *sigh*
Use the new cheddar markdown endpoint to render issue bodies and comment
bodies as JSON. I've checked, and this *also* appears to be XSS
safe (yay)
Change-Id: Ib4b19fd581b0cf40ba03f5d13443535d17df6632
Reviewed-on: https://cl.tvl.fyi/c/depot/+/1500
Reviewed-by: tazjin <mail@tazj.in>
Tested-by: BuildkiteCI
Support a top-level PATCH request to trips that permits any admin to update any
trip, and any user to update any of their trips.
I'm using Aeson's (:?) combinator to support missing fields from the incoming
JSON requests, and then M.fromMaybe to apply these values to any record that
matches the primary key.
See the TODOs that I introduced for some shortcomings.
Display the history of an issue (which currently is just opening and
closing) inline with the issue's comments on the issue show page
Change-Id: Id167bceef765cb4c24e86983d1dcd6624d0e5956
Reviewed-on: https://cl.tvl.fyi/c/depot/+/1497
Tested-by: BuildkiteCI
Reviewed-by: tazjin <mail@tazj.in>
Log in the database, in a way that will generalize to tracking edit
history as well, when users change the status of an issue. To facilitate
easily knowing who is currently authenticated (without introducing a
circular dependency) the authentication-relaated code has also been
factored out into its own package, which is nice because we want to
replace that sooner rather than later anyway.
Fixes: #13
Change-Id: I65a544fab660ed1c295ee8f6b293e0d4945a8203
Reviewed-on: https://cl.tvl.fyi/c/depot/+/1496
Tested-by: BuildkiteCI
Reviewed-by: tazjin <mail@tazj.in>
Even if the user fails to log in, maintain the original-uri param if
present, so that if they eventually succeed at logging in they still get
where they were originally trying to get.
Change-Id: I2faa5eced002ab899c803cf19095cea76897d92d
Reviewed-on: https://cl.tvl.fyi/c/depot/+/1499
Tested-by: BuildkiteCI
Reviewed-by: tazjin <mail@tazj.in>
Add an original-uri query param to the target of the Log In link
pointing at the current URL, so that when the user eventually
successfully logs in they are redirected to the page they were
originally on
Fixes: #21
Change-Id: I75ed7b75fa00b1b09c8b26bf4dcf5bc6b6d7f53a
Reviewed-on: https://cl.tvl.fyi/c/depot/+/1498
Tested-by: BuildkiteCI
Reviewed-by: tazjin <mail@tazj.in>
Somebody incremenet the total number of off-by-one errors that I've made in my
career. I think the current count is 99... or is it 100? 101? Who knows?!
When this was an UPDATE statement with a WHERE clause, and the LoginAttempts
table was vacant, nothing would happen. Thankfully, SQLite supports an UPSERT
clause so that I can INSERT a new record or UPDATE conditionally.
And the best part is: it works!
"SELECT *" in SQL may not guarantee the order in which a record's columns are
returned. For example, in my FromRow instances for Account, I make successive call
The following scenario silently and erroneously assigns:
firstName, lastName = lastName, firstName
```sql
CREATE TABLE People (
firstName TEXT NOT NULL,
lastName TEXT NOT NULL,
age INTEGER NOT NULL,
PRIMARY KEY (firstName, lastName)
)
```
```haskell
data Person = Person { firstName :: String, lastName :: String, age :: Integer }
fromRow = do
firstName <- field
lastName <- field
age <- field
pure Person{..}
getPeople :: Connection -> IO [Person]
getPeople conn = query conn "SELECT * FROM People"
```
This silently fails because both firstName and lastName are Strings, and so the
FromRow Person instance type-checks, but you should expect to receive a list of
names like "Wallace William" instead of "William Wallace".
The following won't break the type-checker, but will result in a runtime parsing
error:
```haskell
-- all code from the previous example remains the same except for:
fromRow = do
age <- field
firstName <- field
lastName <- field
```
The "SELECT *" will return records like (firstName,lastName,age), but the
FromRow instance for Person will attempt to parse firstName as
Integer.
So... what have we learned? Prefer "SELECT (firstName,lastName,age)" instead of
"SELECT *".
Lots of changes here:
- Add the GET /verify endpoint
- Email users a secret using MailGun
- Create a PendingAccounts table and record type
- Prefer do-notation for FromRow instances (and in general) instead of the <*>
or a liftA2 style. Using instances using `<*>` makes the instances depend on
the order in which the record's fields were defined. When combined with a
"SELECT *", which returns the columns in whichever order the schema defines
them (or depending on the DB implementation), produces runtime parse errors
at best and silent errors at worst.
- Delete bill from accounts.csv to free up the wpcarro@gmail.com when testing
the /verify route.
Whichever package is on nixpkgs right now is broken, so I'm using `fetchGit` and
`callCabal2nix`.
Create Email module exposing a simplifies `send` function that partially applies
some of the configuration options.
Using my dear friend's, dmjio's, excellent library, envy -- to read and parse
variables from the system environment.
I added and git-ignored the .envrc file that contains API secrets. I'm using
Envy to read these values, so that I don't hard-code these values into the
source code.
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.
Many Bollywood movies have excellent acting, excellent directing, excellent
storytelling, but in my opinion, they spoil this with unnecessary musicals
interspersed throughout the films.
Dangal is a notable exception here. Overall, I'd say that this movie is
appropriately rated!
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.
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
Now that we've migrated over all the data to postgresql, we can get rid
of cl-prevalence as a dependency from Panettone along with all code that
mentions it.
Change-Id: I945f50a88fea5770aac5b4a058342b8269c0bea2
Reviewed-on: https://cl.tvl.fyi/c/depot/+/1495
Reviewed-by: kanepyork <rikingcoding@gmail.com>
Reviewed-by: tazjin <mail@tazj.in>
Tested-by: BuildkiteCI
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
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.
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
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.