Michal Sojka [Thu, 20 Aug 2020 22:06:28 +0000 (00:06 +0200)]
Ensure that the home screen is loaded automatically
Now, when the application starts, only a blank page is shown. The home
screen (summary graphs for all users) shows only after somebody logs
in and out. With this change, the home screen is loaded automatically
on the first start or on manual page reload.
Together with this change, we split the home and user screens to
separate templates (previously the home screen was the user screen
with name unset). Hopefully, this change makes the UI logic a bit
easier to follow.
Michal Sojka [Tue, 18 Aug 2020 18:13:29 +0000 (20:13 +0200)]
Add event logging
This allows users to log various events such as coffee machine or milk
container cleaning. Also, all users can see when was the last
occurrence of the particular event.
[Credits: This is a modified version of a patch from Jarda Klapálek.]
Michal Sojka [Thu, 30 Jul 2020 06:47:06 +0000 (08:47 +0200)]
Suppress Matplotlib's deprecation warning
The warning was:
coffee-flask/app.py:127: MatplotlibDeprecationWarning:
normalize=None does not normalize if the sum is less than 1 but
this behavior is deprecated since 3.3 until two minor releases
later. After the deprecation period the default value will be
normalize=True. To prevent normalization pass normalize=False
Users can register multiple identifiers for a single account. Also
they can rename identifiers (each identifier has its own name) and
unregister/remove them from the account.
Required: Create new table in database (will be created automatically
on first startup)
CREATE TABLE if not exists identifiers (
`userid` varchar ( 24 ) NOT NULL,
`id` varchar ( 24 ) PRIMARY KEY NOT NULL,
`name` varchar ( 24 ),
`status` INTEGER NOT NULL DEFAULT 1,
FOREIGN KEY(`userid`) REFERENCES `users`(`id`)
);
Note: `status` is used for activating/deactivating associations.
This table creates 1:N relation (users:identifiers), where 'userid'
is marked as foreign key from 'users' table. There is no reason for
changing 'users.id', but it could be done.
Column 'id' is marked as primary key to avoid creating M:N relation
instead. Each time a relation is removed, it is marked as deactivated
and it is deleted from the table next time, when a new relation with
the same identifier is created.
Each coffee is now saved with 'identifiers.id' instead of 'users.id'.
Because we were not using custom id in 'users' table, we do not
have to change anything in currently recorded data/design of tables.
On user creation / first login 'users.id' (or id of identifier) and
id of identifier are added to 'identifiers' table.
Selected changes:
> app.py:login()
From now on we expect that received variable is 'iid' (id of identi-
fier). At first this identifier is checked if it belongs to a user.
If True: 'uid' (users.id) is found in database,
Otherwise: 'iid' is registred as 'uid' for a new user.
> app.py:user_XXX_identifier()
Functions add/rename/disable modifies identifiers for current user.
Note: 'session["uid"]' is used because client side (.js) does not
know the difference between 'uid' and 'iid' (and there is no reason
to change this). This solves a problem of invalid ids when trying to
modify ID#1 of account ID#0 while logged by ID#2 in case we are
assuming that id of identifier ID#0 is the same as 'users.id'.
> app.py:coffee_add()
Add consistency check to avoid situations when user without valid
identifier is trying to register a coffee.
> coffee_db.py
Add functions to match new functions in app.py. Also modify current
functions to use 'identifiers' table in SQL queries.
> coffee_db.py:add_user_identifier()
Creates relation between user and identifier. It is also deleting
old (and deactivated!) relation from the database before registering
a new one.
> templates/main.js:addIdentifier_start() and addIdentifier_finish()
Modifies UI for the user and changes 'identifier_registration' variable.
> templates/user.html
Add table of identifiers for current user, which contains names,
ids and buttons to rename/remove identifier from current account.
Possible TODOs:
- add option to merge two identifiers (e. g. if one is lost, it
should be possible to transfer all coffees to different one),
- divide identifiers to 2+ groups -- 'master key' and 'regular',
so the public ones (e. g. mugs) cannot remove identifiers from an
account.
Add support for another beverages (namely club mate)
Required to run on the server database before using this patch:
```
alter table flavors add ord integer not null default 999;
update flavors set ord=1 where name='cappuccino';
update flavors set ord=2 where name='espresso';
update flavors set ord=3 where name='espresso lungo';
update flavors set ord=4 where name='latte macchiato';
```
This patch slightly changes structure of a `flavors` table. It adds
another column called `ord`, which is used for ordering of coffee
flavors / beverages on the graphs (to maintain the same color scheme).
Scripts `app.py` and `coffee_db.py` are modified to work with this
change.
Michal Sojka [Wed, 27 Feb 2019 15:26:54 +0000 (16:26 +0100)]
Change the name of the configuration file
The reason for this is that the Apache mod_wsgi sets the current
directory of WSGI processes to $HOME and on our server $HOME/.config
is a directory. Instead of changing the working directory of WSGI
processes (which I don't know how to configure), I prefer to use a
different (non-colliding) file name: .coffee.conf. Having the
configuration file outside of the source directory has the advantage
that running "git clean -fx" in that directory does not delete the
configuration, which cannot be easily recovered (our Slack history is
limited).
Jiri Vlasak [Tue, 12 Feb 2019 13:15:35 +0000 (14:15 +0100)]
Add last coffee pack button
When clicked, the message notifying Tonda about the lack of coffee is
sent to the Slack.
There must be `.config` file in `coffee-flask` folder. The `.config`
file is JSON formated. For this patch the following is needed:
```
{
"coffeebot": {
"url": "https://hooks.slack.com/services/..."
}
}
```
Function 'coffee_flavors' wasn't doing what it was supposed to do.
Upper bound was shifted by a day (so for a week graph it was count-
ing 8 days) and also it didn't take into account 'start' variable.
Fix incorrect counting of coffees made during time close to midnight
Datetime in database is stored in UTC timezone. Currently we are in
UTC +2 timezone (GMT +1). Because of time shifts fixing the time
cannot be done in a static way.
Dynamic solution is using paramater 'localtime' in SQL query function
date(). Therefore it is required for the target device to have
properly set timezone.
TODO:
Suggested solution is to use 'type converters' for python/sqlite3.
An error was found during the start of new month. To fix this I have
changed the SQL query to use '%s' (unix time) instead of '%d' (day
number).
How does this work?
The SQL query is using relation between two tables based on the date.
This relation is created using these parts of query:
> "select num,date('now',-num || ' days')" as d from days
> d = date(c.time)
First line creates timestampes of last 7 days -- time is set to
UTC midnight.
Second line converts data in 'c.time' to date struct - BUT! Even
here the time is set to midnight. This behaviour makes the relation
possible.
How does it behave in app.py?
Result of the query contains data that are ordered by time.
Unfortunately this order is lost during recasting the data to
list/dict (which are unordered). To solve this sorting is used.
Sorting data with unix time is safe, because it is always increasing.
To highlight this change, 'days' variable is refactored to 'unix_days'.
Michal [Wed, 15 Aug 2018 10:14:06 +0000 (12:14 +0200)]
Logout automatically even without selecting any beverage
When a user logs in, and no beverage is selected within 120 seconds,
she are logged out automatically.
The main purpose for this functionality that when somebody swipes a
card in the offline mode and than goes away, because she does not see
nice graph. When the server is online again, the offline-collected
data is replayed and the user would stay logged in forever.
Michal [Wed, 15 Aug 2018 10:14:06 +0000 (12:14 +0200)]
Catch all exceptions in JS function updateUI
It fails when offline data is processed. It is important that offline
data are processed entirely and only once. If the code crashes in the
middle, due to an exception, the same offline queue will be replayed
next time, causing some coffees to be accounted multiple times and
some maybe never accounted.
Michal Sojka [Thu, 16 Aug 2018 09:46:55 +0000 (11:46 +0200)]
Improve the last commit
- Move id_user variable to where other variables are defined and
document it.
- Set its value in the login() function. All other activities related
to logging in are in that function, so I don't see a reason, why
this should be outside.
- Unset this variable in addCoffee() and logout(). We should not need
it after these events.
Michal Sojka [Wed, 15 Aug 2018 10:14:06 +0000 (12:14 +0200)]
Use button element instead of input
It seems that the web browser on the terminal does not understand '\n' in
value attribute so I hope that it will understand '<br>' in button's
content.
Michal Sojka [Tue, 14 Aug 2018 22:38:17 +0000 (00:38 +0200)]
Attempt to sanitize the JS code + fix few bugs
The problems solved by this commit:
- When another user logs in during logout timeout, he was logged out
automatically, even before choosing a coffee.
- Logout timer was not shown always when it should. After choosing a
coffee, the timer was shown for a while. Then, after the user page
was reloaded from the server, the timer disappeared and after an
elapsed second, the timer was shown again.
- Local debug area was not shown and hidden consistently.
The first problem was resolved by canceling the logout timer after
login. The last two problems were fixed by centralizing of the UI
updates to a single function, which does the update based on the value
of state variables.
Michal Sojka [Tue, 14 Aug 2018 21:25:04 +0000 (23:25 +0200)]
Unify logout button spelling and layout
Changes:
- Logout button text is always in small caps (both initial value from
HTML and modified value from JavaScript).
- Position of the "logout" text is always the same - when we add a
line with seconds counter below, we have to add also a line above.