30 Commits

Author SHA1 Message Date
Jonathan Bernard
f3ef7db088 Work on front-side UI.
* Resolved D0003: Add day separators.

    * Created ``daySeparatorTemplate`` for ICanHaz templating.
    * Refactored ``EntryListView.render`` to spit out day separators in between
      days on the timeline. Fixed the "Today" separator to the top of the entry
      container. We no longer prepend entries to the entry container, we now put
      them after the top separator in the entry container.
    * Created ``EntryListView.formatDaySeparator`` to format the labels
      according to the relative time to today: "Yesterday", "Last Monday",
      "Friday, May 28" for example.
    * Removed the cludgier ``toWords``, ``daysApart``, and `` capitalize``
      functions that were going to serve the same purpose.
* Resolved D0021: Constrain notes width to mark.
2011-06-17 16:11:18 -05:00
Jonathan Bernard
1fff94b622 Implemented entry exclusions in UI.
* Resolved D0020: Add exclusion filter for entries.
* Refactored ``timeline`` fields of several objects in ``ts.js`` to be
  ``timelineModel`` to be explicit.
* Added support for exclusions in ``EntryListView.renderOne`` and
  ``EntryListView.render``.
2011-06-16 17:55:01 -05:00
Jonathan Bernard
602bdca7e3 Minor fixes needed for last_timeline to work.
* Added route back for PUT /ts_api/user/<username>
* Fixed typo in ``ts_api:put_user/2``.
* Fixed incorrect expected return from ``ts_ext_data:set_property/3``.
* Added missing assignment for ``ts_user.email`` in the appropriate
  ``ts_json:construct_record/3`` clause.
* Fixed model attribute assignment in ``ts.js``.
2011-06-15 18:31:53 -05:00
Jonathan Bernard
cd182d54c3 Fixing problems introduced by the model change.
* Many calls to ``ts_ext_data:get_properties/1`` from ``ts_api`` were passing
  the record reference, not the record itself. Fixed.
* Created ``ts_api:put_user/2`` which updates a ``ts_user`` record. This is
  needed specifically for updating the ``liat_timeline`` extended data property.
* Removed unreachable code in ``ts_api:post_entry/3``
* Fixed return value of some ``ts_user`` functions to use the
  ``{Status, Value}`` convention. TODO: make sure all calls are using the same
  convention.
* Fixed error message formatting in ``ts_ext_data:set_property/3``.
* Added clauses to ``ts_json:ejson_to_record/2``,
  ``ts_json:ejson_to_record_strict/2`` and ``ts_json:construct_record/3`` to
  handle the ``ts_user`` record type.
* Added code to ``AppView.loadInitialData`` and ``AppView.selectTimeline`` to
  support the ``last_timeline`` extended data property.
2011-06-15 16:59:00 -05:00
Jonathan Bernard
3999e736be Bug fixes and implementation refinement around `ts_ext_data`.
* Transformed the test database to match the new data model. Added
  ``ts_ext_data`` table and moved ``ts_user.ext_data`` values to it.
* Added D0022: cascade delete ``ts_ext_data`` when ``ts_entry`` record is
  deleted.
* Completed refactor of ``ts_api`` functions to account for extended data:

    * ``post_entry/3``
    * ``put_entry/3``

* Created ``ts_entry:write/2`` to write extended data atomically with the entry.
* Fixed copy/paste bug in ``ts_ext_data:create_table/1``.
* Fixed implementation of ``ts_ext_data:set_property/3`` to be explicit about
  taking a record, not a reference. It then extracts the reference and passes it
  to the underlying implementation in ``ts_ext_data:do_set_property/3``.
* Refactored ``ts_ext_data:do_set_property/3`` to take a record *reference*, not
  the record itself.
* Refactored the ``ts_ext_data:get_property/2`` and
  ``ts_ext_data:get_properties/1`` functions to return key value tuple pairs,
  not ``ts_ext_data{}`` records.
2011-06-15 07:34:41 -05:00
Jonathan Bernard
8bb50c058d Changed Data Model
------------------

* Created the extended data table. This is a more generic version of the
  extended data field that was on ``ts_user``. Instead of arbitrary key-value
  pairs going in a list on the user record we will have an additional table, a
  one to many relationship between existing tables and the ``ts_ext_data``
  table, each row being an extended value of the corresponding record.
* Added support to the ``timestamper:create_tables/1`` and
  ``timestamper_dev:create_table/1`` functions for the new ``ts_ext_data`` table.

Documentation
-------------

* Added some general docs about the DB layer code.
* Added two new issues, *D0020*: Entry exclusion filters and *D0021*: notes width.

API Changes
-----------

Necessitated by the change to the data model.

* Updated ``ts_api`` data-retrieval functions to use extended data:

    * ``get_user_summary/2``
    * ``list_timelines/2``
    * ``list_entries/3``

* Updated ``ts_api:put_timeline/3`` to parse the extended data supplied by the
  caller. *FIXME* it is not actually saving this data.
* TODO: Started updating ``ts_api:post_entry/3`` to handle extended data, need
  to finish.

Database Layer
--------------

Changes necessitated by the change to the model.

* Added ``ts_common:do_set_ext_data/2`` which iterates through the extended data
  key-value pairs calling ``ts_ext_data:set_property/3``. It does not provide a
  transaction context.
* Split ``ts_common:new/1`` and ``ts_common:update/1`` functions into multiple
  functions to prevent code-duplication:

    * ``do_{new,update}`` contains the code that performs integrity checks and
      the actual database write function. It does this assuming that it is being
      called from within the context of an mnesia transaction (uses
      ``mnesia:read`` and ``mnesia:write``).
    * ``{new,update}/1`` performs the same function as previously. The
      implementation changed from using mnesia ``dirty_*`` calls to prociding a
      transaction and calling ``do_{new,update}/1``.
    * ``{new,update}/2`` expect the record to update/create and the extended
      data to write atomically with the record. They provide a transaction
      context, call ``do_{new,update}/1``, then call ``do_set_ext_data/2``.

* Similar to the refactoring of ``ts_common:{new,update}/1``,
  ``ts_entry:{new,update}/1`` have been refactored into multiple methods each to
  support extended data properties:

    * ``do_{new,update}/1`` perform the actual update assuming we have already
      established an mnesia transaction.
    * ``{new,update}/1`` behave the same as they used to, but now do so by
      creating an mnesia transaction and calling ``do_{new,update}/1``.
    * ``{new,update}/2`` create an mnesia transaction, call
      ``do_{new,update}/1``, and then call ``ts_common:do_set_ext_data/2``.

* Again similar to the refactoring of ``ts_common:{new,update}/1``,
  ``ts_user:{new,update}/1`` have been refactored into multiple methods each to
  support extended data properties:

    * ``do_{new,update}/1`` perform the actual update assuming we have already
      established an mnesia transaction.
    * ``{new,update}/1`` behave the same as they used to, but now do so by
      creating an mnesia transaction and calling ``do_{new,update}/1``.
    * ``{new,update}/2`` create an mnesia transaction, call
      ``do_{new,update}/1``, and then call ``ts_common:do_set_ext_data/2``.

* Created the ``ts_ext_data`` module as the interface to the extended data
  properties introduced in the data model:

    * ``create_table/1`` performs the same function as it does in the other db
      layer modules, creates the table with the appropriate structure given the
      more general table options desired (location, storage type, etc.).
    * ``set_property/3`` takes a record, a property key, and a property value as
      input and sets the property described by the property key on the record to
      the given value, assuming this is a valid property for the record to have.
      For example, currently the ``ts_user`` record can have an associated
      property, ``last_timeline``, which represents the last timeline the user
      was working with. Trying to pass this property with a ``ts_entry`` record
      would result in an exception. This function uses
      ``ts_ext_data:do_set_property/3`` as its underlying implementation.
    * ``get_property/2`` takes a record and a property key and returns the value
      of that property for the given record, or ``not_set`` if the property has
      not been set on that record. This method creates its own mnesia
      transaction.
    * ``get_properties/1`` takes a record and returns a list of key-value tuples
      representing all of the extended data properties set for the given record.
      This method creates its own mnesia transaction.
    * ``do_set_property/3`` takes a record reference (not the whole record), a
      a property key, and adds the property assignment to the ``ts_ext_data``
      table. It creates its own mnesia transaction.

* Added ``new/2`` and ``update/2`` to the ``ts_timeline`` module to support
  extended data properties. They delegate implementation to
  ``ts_common:{new,update}/2``.

JSON Encoding/Decoding
----------------------

Changes necessitated by the change to the data model.

The JSON objects now contain a potentially unlimited number of fields, as each
extended data property is encoded as a seperate field, and looks no different
from any of the required fields on the object. The intended explanation in API
documentation is that each object type (``user``, ``timeline``, or ``entry``)
now has both *required* fields that *MUST* be present in every message in either
direction and *optional* fields that may or may not be present in any
communication with the API. There should be a clear distinction between which
fields are required and which are optional. It might also be a good idea to
provide a suggested default for optional values when they are not present.

* Updated documentation about JSON record structures to reflect the fact that
  there are now potentially many optional attributes in addition to the required
  attributes for each record.
* ``record_to_ejson/1`` refactored to ``record_to_ejson/2`` which also takes
  the extended data attributes and appends them as additional attributes to
  the end of the record structure.
* Created ``ext_data_to_ejson/{1,2}`` to provide a mechanism for reformatting
  extended data properties whose internal representations are not immediately
  translatable into JSON. Currently only the ``entry_exclusions`` property,
  which is a list of strings, needs to be treated this way (changing from
  ``[val, val]`` to ``{array, [val, val]}`` as needed by ``json:encode/1``.
  ``ext_data_to_ejson/1`` acts as a more user-friendly facade to
  ``ext_data_to_ejson/2``.
* Rewrote ``ejson_to_record/{2,3}`` and ``ejson_to_record_strict/{2,3}`` to
  handle extended data. They now use a common method, ``construct_record/3`` to
  create the actual record object and extended data key-value list.
  ``ejson_to_record_strict/{2,3}`` only differs in that it checks for the
  presence of each required field of the record after the record is constructed.
  The three-parameter versions of these functions also take in the intended
  reference for the constructed record, replacing anything that is in the EJSON
  body as the record reference (useful when the body does not have the record
  ids). These methods now return a tuple: ``{Record, ExtData}`` instead of just
  the record.
* Created ``construct_record/3`` takes a record and the EJSON fields from the
  input object. The third parameter is an accumulator for the extended data
  properties found when constructing the record. This method works by iterating
  over the list of input fields. It recognizes any required fields and updates
  the record being built with the value. Any fields it does not recognize it
  assumes are extended data properties and adds to its list. When all input
  fields have been visited it returns the record and list it has constructed.
* ``ejson_to_ext_data/{1,2}`` is the inverse of ``ext_data_to_ejson/{1,2}``.
  *TODO*: this method is not actually being used by the ``ejson_to_record*``
  methods.
2011-06-14 16:48:04 -05:00
Jonathan Bernard
99d04935cb Implemented timeline selection.
* Added personal VIM ide extension.
* Implemented timeline selection (resolves D0007)
* Slightly restyled the new timeline button and timeline list menu.
2011-06-10 11:49:45 -05:00
Jonathan Bernard
cf42d133f6 Added UI for timeline creation. 2011-06-01 06:29:48 -05:00
Jonathan Bernard
2cc17b85f1 Implemented notes UI.
- Switched from a global reset in www/css/ts-screen.scss to a selected
  top-level elements reset to allow default formatting for user notes.
- Restructured the #entry-list and entry displays.
- Restructured notes div, now has a sub-div for text and a textarea
  element for input.
- Added Showdown.js, a JavaScript Markdown library for formatting comments.
- Moved EntryView blur events to the View events map.
- Added images for expansion of notes.
- Added the ability to edit notes.
- Split EntryListView.addOne into renderOne and addOne so that renderOne
  can be called with a new entry (fixes duration glitch)
2011-05-16 04:09:37 -05:00
Jonathan Bernard
65a9a517f9 Updated test data. 2011-05-09 10:54:24 -05:00
Jonathan Bernard
850edf9e25 Updated test data. 2011-05-07 21:30:00 -05:00
Jonathan Bernard
cf5153c90b Merge branch 'api-redesign' into client-redesign 2011-05-03 12:40:06 -05:00
Jonathan Bernard
ebd4b117c9 Updated database to use lists instead of atoms for table keys. 2011-05-03 12:27:13 -05:00
Jonathan Bernard
302bc9ccdd Trying to gather thoughts and code coherently.
Added client-side architecture model.
Playing with UI code.
2011-04-27 14:11:54 -05:00
Jonathan Bernard
9025a2f8f6 Trying a view for user, timeline(s), entry(ies). 2011-04-20 09:40:54 -05:00
Jonathan Bernard
e10ec26a21 Implementing new client design using Backbone.js. 2011-04-15 13:26:55 -05:00
Jonathan Bernard
4d124ffeba Fixing dev config. Starting to implement sign-up.
Added 'default' make target to only compile.
Reset development configuration.
Commented out starts of tests.
Added sign-up GUI to login panel.
Moved application from /ts/ to /
2011-03-16 07:39:09 -05:00
Jonathan Bernard
39c3b83d3f Implemented edit and update for entries.
- Added ts_entry:delete/1 to delete an entry from the database.
- Implemented ts_api:delete_entry/3.
- Added a form to facilitate editing individual entries.
- Moved the small show/hide functions directly into the HTML.
- Wired up the update timeline form.
- Wired up the edit and update entry form.
2011-03-08 18:02:33 -06:00
Jonathan Bernard
1b1e31059b Implemented entry creation, pagination. Some restyling and bugfixes.
- Bug fix in ts_api:list_entries/3. Case statement matching on atoms but
  input is a list (string).
- Bug fix in ts_api:put_entry/3. Was expecting the wrong result from
  ts_entry:new/1.
- Bug fix in ts_entry:list/4. Code crashed when the starting offset was
  greater than the total number of elements. Now returns [].
- Fixed ts_json:encode_datetime/1 and ts_json:decode_datetime/1 to handle
  millisecond values in the datetime string (per ISO standard).
- Broke out ``control-links`` style to a top-level class.
- Added showdown.js, a JS Markdown processor. Not hooked up to anything
  yet but intend to display entry notes with Markdown.
- Added code for entry pagination. Loads the most recent 20 entries and
  loads more upon demand in batches of 20.
- Fixed bug in login routine that kept the user edit fields from being
  pre-populated.
- Rewrote the loadEntries function to double for new entries and loading
  more existing entries.
- Commented displayEntries. Also refactored into displayNewerEntries,
  which pushed new entries on to the top of the stack, and
  displayOlderEntries, which tags them onto the bottom.
- Implemented hidden notes field for new entry input.
- Implemented new entry creation.
- Created a helper function to ISO format a Date object.
- Expanded entry template to show control links (edit, show notes, del).
- Activated the 'load more entries' button.
2011-03-07 16:43:40 -06:00
Jonathan Bernard
c185c8cd81 Deciding on UI for entry list. 2011-03-06 13:46:18 -06:00
Jonathan Bernard
122a3bd1e3 Started implementing entry loading in client side.
- Bug fix in ts_entry:new/1. Msspelled ``atomic``.
- Bug fix in ts_json:record_to_ejson/1. For ``ts_entry`` records, the
  Username and TimelineId elements were not being converted from atoms to list.
- Added the entry template for loaded and created entry elements.
- Added ICanHaz.js (which wraps mustache.js) and underscore.js.
- Implemented a naive version of displayEntries() in ts.js.
- Added debug alerts for error cases in ts.js.
- Styling the new entry elements.
2011-03-03 17:09:13 -06:00
Jonathan Bernard
348c73a36f Bugfix and documentation.
- Fixed a bug in ts_api:list_timelines/2 and ts_api:list_entries/3, which
  respond only to GET requests but were looking for POST data.
- Added documentation for ts.js.
2011-03-01 18:00:51 -06:00
Jonathan Bernard
439a080f14 Started adding implementation of client-side functionality.
- Changed ts_api:dispatch_user/3 to return information for the user currently,
  authenticated if a valid session id is presented and no username is presented.
- Moved the generic styling of form > * elements to be specific to .bar > form.
- Added jQuery U 1.8.0.
- Created login dialog that will automatically load upon page load if the user
  is not logged in.
- Added styling for jQuery UI login dialog.
- Implemented login functionality on the client page.
- Implemented functionality to load user and timeline records on the client
  side.
2011-03-01 08:23:51 -06:00
Jonathan Bernard
4492f87a39 Added user_summary to api.
Added ts_api:dispatch_app/3
Added ts_api:get_user_summary/2
Fixed compile errors in ts_user.
Added comments.
2011-02-24 07:29:30 -06:00
Jonathan Bernard
dcd836ba8e Testing out design ideas. 2011-02-11 08:32:12 -06:00
Jonathan Bernard
afca12ecc9 Started working on the client-side code. 2011-02-10 07:47:35 -06:00
Jonathan Bernard
0642c18a6e Implemented cookie-based authentication to the API.
Created timestamper module to start the application.
Added cookie-based authentication to ts_api.
Added utility methods to ts_api:
    * make_json_400/1 and make_json_400/1
    * make_json_401/1 and make_json_401/2
    * parse_json_body/1 reads a JSON object from a HTTP request body.
Implemented ts_api_session module to manage api user sessions.
Fixed ts_entry:list* methods to be 0-indexed.
Removed the ts_json:ejson_to_record/1 implementation for ts_user records.
    Decided that ts_user records are never trusted from the client,
    manipulation of fields such as pwd, username will be restricted to
    app pages.
Changed the password hashing algorithm. Now uses SHA1(pwd + 256bit salt).
    Want to use bcrypt, investingating cross-platform bcrypt implementation.
Fixed yaws.conf config file.
2011-02-07 08:56:07 -06:00
Jonathan Bernard
6e2e0d5f00 Redesigned API URL structure. Updated ts_api to implement this.
Implemented ts_api:list_timelines/2.
Adjusted ts_timeline:list/3 to be 0-indexed.
Changed ts_user password hash to use a random salt + SHA1
Added some skeleton testing code.
2011-02-04 17:19:53 -06:00
Jonathan Bernard
1575e25898 Implemented ts_api:get_user/2, ts_api:put_user/1, and ts_api:post_user/1.
Created a utility function for OK results, ts_api:make_json_200/2
Created ts_common:new/1 and ts_common:update/1 to generalize record creation and update.
Refactored ts_timeline:new/1 and ts_timeline:update/1 to use the ts_common functions.
Implemented ts_json:record_to_ejson/1 and ts_json:ejson_to_record/1 for ts_user records.
Implemented ts_user module.
2011-02-03 17:23:40 -06:00
Jonathan Bernard
6fe9184c8e Continuing work on the API.
The id_counter module now includes the record directly in the source.
Fixed many typos and small syntax errors.
Added ts_api:dispatch_user/2 to handle different HTTP methods.
Added method placeholder stubs to ts_api.
Implemented ts_api:list_entries/3.
Added ts_user record and ts_user module.
Implemented ts_entry:list/4, the more generic guts of the other list functions.
Created ts_entry:list_asc/3 and ts_entry:list_desc/3.
Fixed ts_json:encode_datetime/1.
2011-02-02 16:57:58 -06:00