Commits on Oct 20, 2018
  1. Add support for the iframe tag (#639)

    johansmitsnl authored and paulcsmith committed Oct 20, 2018
    Add support for the iframe html tag
Commits on Oct 19, 2018
Commits on Oct 18, 2018
Commits on Oct 13, 2018
  1. Improve gen.resource.browser (#629)

    citizen428 authored and paulcsmith committed Oct 13, 2018
    * Add "New" link to index page
    * Add link back to index page from show page
    * Remind user to run migrations
Commits on Oct 11, 2018
  1. Adds some extra specs. fixes #601 (#626)

    jwoertink authored and paulcsmith committed Oct 11, 2018
    * Adds specs to confirm that using a HEAD request on a GET route works with latest LuckyRouter update. fixes #601
    * using master branch of lucky_router so tests pass in CI.
    * no need to assert content-type on this spec. Updated API
  2. Refactor the cookie system (#609)

    edwardloveall authored and paulcsmith committed Oct 11, 2018
    * CookieJar
    * Add clear
    Also add optional get? method for getting values
    * Edward did it
    * Read it real good
    * Ensure cookies can be used in actions
    We're removing the [] methods because we don't want cookies to be a
    Also remove session for now since it's hard to do both at once
    * Start to test better_cookies
    * Test the plain adapter
    This reads and writes cookies from a request/response respectively, in
    plain text (albeit encoded). This will be replaced with a version that
    encrypts the cookies, but for now, we're working with this.
    * SessionHandler sets a cookie for the new class
    Again using the PlainAdapter
    * Write cookies to the context if they exist in the headers
    * Add EncryptedAdapter to encrypt cookies
    This takes advantage of the MessageEncryptor class to encrypt and
    decrypt a cookie's value. The key remains unencrypted (perhaps
    obviously) but the value is encrypted with the app's secret_key_base.
    The key must be 32 digits long (e.x. 16 hex pairs) or longer to be
    valid for the encryptor. Because of this, I changed the secert_key_base
    in the spec_helper.
    I also encoded the result of the message encryptor. Currently it
    encrypts it and returns raw bytes. I thought having a string
    interpretation would be nicer to look at and use. I looked into the
    hexstring method but there was no built-in way for me to get back out
    of the hexstring that I could find. Base64 worked great.
    * Fix cookies being accessed on the action
    Turns out having cookies on the context is really helpful for working
    with it, not just in actions, but everywhere. So I moved it back there.
    * AbstractStore
    Because a SessionStore and a CookieJar are going to be almost identical
    * SessionStore
    This will be used to coordinate with the CookieJar. It can turn it self
    into a single encrypted and base64 encoded key/value pair to be placed
    on a cookie. It has no sense of adding itself to headers. Some adapter
    or other class will take care of that.
    * Store each cookie individually instead of in a big JSON hash
    I have set cookies in actions so that I could use them in the view via
    JavaScript. Our session cookie should be encrypted, but by default, I
    think storing each cookie separately is fine and expected. This,
    incidentally, is also how Rails does it (I think).
    * Cookie and Session are fetched lazily
    When the cookies are accessed from an action, they are automatically
    read and parsed from the request. They are memoized so as to only slow
    down the request when necessary.
    When the session is accessed from an action, is uses data from the
    cookies to retrieves its contents. This will call the cookies as
    describe above. The session will then also be memoized.
    * Store cookies as a combined JSON hash
    We decided that it would be better for the cookies to be encrypted, and
    also to be combined into one large hash. I thought rails had plain text
    cookies, but it turns out that's not true.
    Next up will be encrypting them
    * Replace PlainAdapter with EncryptedAdapter
    * Set cookie expiration to 1 year
    * WIP action session test
    * Fix session handler spec
    Turns out, I was setting the Cookie header incorrectly. It's not the
    same as the Set-Cookie header. Cookie only has name=value; as its
    format, where Set-Cookie has all the extra data about expiration, path,
    HTTPOnly, etc.
    * Fix type inference on old CookieStore
    * New encrypted adapter
    It's different from the old Encrypted adapter in that it doesn't bother
    with compressing all the cookies into a single JSON store, but it
    stores them each as separate cookies. Internally we're still using a
    hash with the CookieJar
    * Write encrypted cookies to Set-Cookie header
    * Use new encrypted cookie adapter
    * CookieJar is now an extension of HTTP::Cookies
    This is so other attributes on cookies can be set. For example if you
    want to set an expiration for a cookie, you need access to the raw
    cookie, or Lucky would have to essentially reimplement cookies work and
    they work fine for the most part.
    The only thing we'll be doing is encrypting/decrypting all their
    values. That's up next.
    I also removed the key setting because there's not a single key for
    cookies. There will be a single key for the session though.
    * Add a encrypted processor
    Yet another take on encrypting cookies. This one loops through each
    cookie and encrypts the value and then writes it to the headers, or
    reads and decrypts each cookie.
    * Add SessionCookie
    SessionCookie is a wrapper around a Hash. It represents a single cookie
    key/value pair. The key is set by a Habitat setting, while the value is
    a hash that will be converted to JSON and stored with the encrypted
    * Remove unused adapters
    I went with processors instead
    * Remove unused specs
    * Change interface to the CookieJar
    This was changed primarily so that we could abstract away the actual
    cookies object in case it changed, and also so you can only set/get
    cookies with a symbol or string. HTTP::Cookies lets you use any object
    as a key which we didn't feel was safe enough.
    abstract away the actual cookies object in case it changed, and also so
    you can only set/get cookies with a symbol or string. HTTP::Cookies
    lets you use any object as a key which we didn't feel was safe enough.
    'el-cookie-refactor' on '92d45bb'.
    * Set the retrieve the session from cookies
    The session is now a single cookie with a name ending in "_session" and
    starting with the name of the app (eventually). It is encoded with the
    cookies when they are written to the response and can be fetched from
    the cookies in the request with their preset key.
    Changing the key will invalidate the session because it will start
    * Introduce NullCookie
    NullCookie is a HTTP::Cookie-like object that is meant to have a
    similar API and respond to most of the same getters. For each value, it
    returns nil or false.
    It's now used when retrieving a cookie with the get?() method. If there
    is no cookie with the specified key, it will return this NullCookie.
    That way people can call all the normal methods on the cookie without
    the app crashing.
    * FlashStore
    This implements a store for Flash messages. In particular exposing
    failure, info, and success methods for commonly used flash messages.
    * Test that you can use the flash in actions
    * Refactor FlashStore so it erases it self each request
    For some reason I thought I could have a single store, but I couldn't.
    Now the flash has two stores, now and next. Now can only be set from a
    value stored on a session. Next is a more traditional mutable store.
    It's what will be changed when actions call flash.set(key, value).
    Eventually, the flash will be saved to JSON and written out to the
    session, which will in turn be written out as a cookie to the browser.
    * Create FlashHandler to export the flash to the session
    This is similar to the session handler, but uses the session as the
    store for the Flash instead of a cookie. The session of course
    eventually turns into a cookie, but the Flash handler doesn't care.
    The flash handler also only submits the "next" flash to the json, which
    gets read in as the "now" flash. This ensures that the flash only
    sticks around for one request/response cycle.
    * Set far-future expiration dates on cookies
    I chose 1 year which seems like a reasonable default for most apps.
    It's not yet configurable unless you manually grab the cookie and set
    it yourself.
    I also had to change the encryptor around a little bit so it used the
    expiration date that I set. This also caused me to change a test in the
    session handler spec. Now when you call the SessionHandler, it will
    encrypt all the cookies on the context as opposed to writing new ones
    to a response. Because of this, the cookies I was reading to test if
    they could be transferred from session to session weren't readable
    because they got encrypted.
    But, it turns out that I don't want to call the SessionHandler with the
    new context anyway since in a real world scenario the cookies will be
    accessed before the session handler really finished.
    * Dirty hack to fix cookie expiration spec
    This works when I test just this file but not in the full suite. My
    guess is because the time set in the cookie jar is a constant that is
    set at compile time, which ends taking more than 1 second to compile. 1
    minute difference for a year seems reasonable for now.
    I tried to get to work but even that showed differences in
    time of more than one second.
    * Extend HTTP::Cookie to be chainable
    This provides a nice interface to an HTTP::Cookie that makes it easy to
    chain the setting of values.
    * Redo object alias
    For some reason, this is not compiling anymore when it's the
    module::class name without being wrapped in the module. It works like
    this though ¯\_(ツ)_/¯
    * Move session handler spec to the right location
    How'd you get out here?!
    * Remove old cookie/session/flash code
    * Don't write cookies or session if they haven't changed
    This tracks a @Changed instance variable on the CookieJar and
    SessionCookie. It starts as false and changes to true any time the
    `set` method is called.
    The reason we want to check if any cookies have changes is sending the
    Set-Cookie headers back in a response makes the response larger. If no
    cookies have changed, we can save bandwidth and gain speed by just not
    sending them in the request.
    If the session hasn't been saved, it doesn't get set on the cookie. If
    they session has changed however, it will set a new cookie which marks
    the cookies as having changed and therefore will send the Set-Cookie
    header in the response.
    * Format crystal code
    * Ensure cookies are HTTPOnly by default
    I also added some tests on CookieJar to ensure that the cookie
    expiration date has a good default and also can be overridden. I
    removed the equivalent expiration test from the session handler since
    it doesn't really belong there.
    * Raise error if cookie size is over 4096 bytes
    Most browsers don't support cookie headers that carry more than 4096
    bytes of data. This will raise an error if someone is trying to write
    cookies that are bigger than that.
    The tricky thing is the encryptor will give a slightly different output
    every time it's written, so you could theoretically have some cookies
    that are 4090 bytes one write, and 4097 bytes the next which will trip
    this error. Not quite sure what to do about that.
    * Remove shadow variable
    Ameba complained about this, which is fair.
    * Test that the cookie headers are all set property
    Just double checking that I set the cookie path, expires, domain,
    Secure, and HttpOnly attributes on the cookie header.
    * rename BetterCookies module to Cookies
    * Update action callbacks spec after rebase
    * Add debug messages back to spec
    These went away during a rebase
    * Fix Typos
    * Use span for cookie expiration instead of time
    The problem with using a Time as a constant is that the date is based
    on the running crystal process. So for example if you boot up the app
    on Jan 1, 2018 1 year from now will be Jan 1 2019. If the app continues
    to run, that 1 year from now date will not change.
    So instead I'm storing it as a Time::Span (or Time::MonthSpan) and
    converting it to a time just as I set the cookie so it will calculate
    from the time the cookie is set, not the time the app was booted. In
    addition, I made it a habitat setting so it could be configured by the
    I could have used a method too, but that wouldn't have been
    configurable with habitat.
    * Use try instead of a fallback to setup the session and flash
    This is so we don't have to waste time parsing empty sessions or flash
    * Create nilable versions of the flash shortcut methods
    * Crystal formatter
    * Add support folder to load message encrytor
    This was being loaded implicitly before inside of the old cookie code,
    but now we need to make sure it's added more explicitly.
    * Improve test for action cookies and session
    * Change cookie expiration name to reflect is purpose
    Any cookie's expiration can be changed using the expires method, but we
    set a 1 year expiration by default. Since it's a default,
    default_expiration better reveals the purpose of the setting.
    * Restore YAML
    This was required in the old cookie code because it was used there, but
    it is also used in the server settings. Since I removed the old cookie
    code, it was failing to run when creating a app with this version of
    * Add an interface to remove cookies and session keys
    To unset a cookie, you must set the same cookie's expiration to a date
    time in the past.
    * Remove nil fallback from Flash because it's not needed
    get? already returns nil if the key has no value
    * Flash.danger -> .failure
    * Spec cleanup
    Fixing typos, simplifying values, and adding a test for flash messages
    being available on the next request.
    * Raise helpful JSON parse error instead of swallowing it
    Now if for whatever reason the flash stored inside the session isn't
    valid JSON the developer will get an error and the bad JSON so they can
    report a better error.
    * Require session cookie to be set with a Cookie
    It was a bit risky to have the session be a NullCookie by default, so
    instead we require it to use an HTTP cookie.
    However, now the cookie needed a way to bootstrap itself. I added a
    session_cookie method to CookeJar that would return the stored cookie,
    or make a new blank one ready for the session to eat (I mean initialize
    * Avoid early returns
    * Clarify multiple request cookie spec
    * crystal tool format spec src
Commits on Oct 8, 2018
  1. allowing the AllowedInTags to be used as attribute values. fixes #483 (

    jwoertink authored and paulcsmith committed Oct 8, 2018
    * allowing the AllowedInTags to be used as attribute values. fixes #483
    * formatting
    * added spec for link helper to ensure it can take attributes with values that are not just strings
Commits on Oct 7, 2018
  1. added script to run tests and related commands (#621)

    ajwann authored and paulcsmith committed Oct 7, 2018
    * added script to run tests and related commands
    * also format the spec directory
    * make wording a bit more verbose
    * add step to 'contributing' section about running bin/test
    * contributors should probably make changes before running ./bin/test
Commits on Oct 5, 2018
  1. Add release task (#602)

    HarrisonB authored and paulcsmith committed Oct 5, 2018
    * Add release task
    * Add tests for release build task
  2. Fix small typo

    paulcsmith committed Oct 5, 2018
  3. added documentation for the uploaded_file class (#618)

    ajwann authored and paulcsmith committed Oct 5, 2018
    * added documentation for the uploaded_file class
    * add class description
    * ran 'crystal tool format spec'
  4. added documentation to the welcome_page class (#617)

    ajwann authored and paulcsmith committed Oct 5, 2018
    * added documentation to the welcome_page class
    * mark methods besides render as private
Commits on Oct 4, 2018
Commits on Oct 3, 2018
  1. Ability to pass in "valueless" attributes. Fixes #518 (#549)

    jwoertink authored and paulcsmith committed Oct 3, 2018
    * WIP: Initial work on adding in boolean attributes (aka valueless attributes)
    * This single spec passes, but man does this feel hacky lol
    * uncoment the specs for custom_tags. Adding override method to catch when an empty NamedTuple is being passed in. Guess what? Crystal crashes....
    * make this consistent
    * spec passes, and crystal doesn't crash
    * cleanup tons of duplication. Feels a lot better
    * boolean attributes work for standard nestable tags
    * regular tags and inline tags now support boolean attributes
    * fixing broken specs
    * added attrs option to input helpers like text_input and such
    * space.... the final frontier
    * updating specs to remove trailing slash per new updates
  2. fixing css_link method. Fixes: #614 (#615)

    jwoertink authored and paulcsmith committed Oct 3, 2018
    * fixing css_link method to output empty link tag instead of link tag with a closing link tag. Fixes: #614
    * rename inline_tag to empty_tag to follow convetion. Added a spec for consistency
Commits on Sep 14, 2018
  1. Add method for type-safe skipping

    paulcsmith committed Sep 14, 2018
    Closes #608
  2. Log exception and backtrace to STDOUT

    paulcsmith committed Sep 14, 2018
    Closes #606
  3. Log action callbacks

    paulcsmith committed Sep 14, 2018
    Closes: #604
Commits on Aug 29, 2018
Commits on Aug 28, 2018
  1. Update Habitat to 0.4.0

    paulcsmith committed Aug 28, 2018
  2. Add support for HTTP responses with files (#589)

    jayroh authored and paulcsmith committed Aug 28, 2018
    Similar to Rails' ActionController [send_file] method, this commit adds
    support for the renderable class to not only render text, but to also
    respond with the contents of a file.
    This also allows for designating whether a file should be downloaded
    upon hitting the action, or rendered inline (for images, or maybe a text
Commits on Aug 24, 2018
  1. Add in some helpful text (#587)

    paulcsmith committed Aug 24, 2018
    Closes #569
  2. Update button styles (#586)

    paulcsmith committed Aug 24, 2018
    Closes #568
  3. Remove LuckyMigrator

    paulcsmith committed Aug 24, 2018
    Because it has been merged into LuckyRecord
Commits on Aug 23, 2018
  1. Update (#583)

    westonganger authored and paulcsmith committed Aug 23, 2018
  2. Add to_h method to params. Fixes #415 (#578)

    jwoertink authored and paulcsmith committed Aug 23, 2018
    * added params to_h method. Works for body_params only right now
    * uncomment spec now that 491 was merged
    * merge params in to_h call
    * fixing to_h on params to support when json params are used. Added spec for this. A few small cleanups
    * added multipart spec for params to_h
    * merge query params in to json params for to_h method so it catches both. Updated spec
    * ran the formatter
  3. Add custom config to log handler output. fixes #480 (#541)

    jwoertink authored and paulcsmith committed Aug 23, 2018
    * initial work on being able to customize the log handler output. This commit actually tanks crystal, so for now, this is WIP
    * moving log format to separate class with abstract parent. Added spec for testing custom logging with emojis
    * ran format tool.
    * using the newest habitat temp_config option for log handler specs
    * moved timestamp method in log handler to class level. This cleans up duplication in log formatter a little