New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Introduced 'Remember me' functionality #470
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hello!
Thank you for your contribution to ListenBrainz! When you create a pull request, please also add a link to a ticket if one exists (https://tickets.metabrainz.org/projects/LB/issues/LB-398?filter=allopenissues)
I'd like to make a few suggestions to this change. You'll note that in the ticket we added a number of items that should be checked before completing this task. It would be great if you could test the following items and add a comment to the ticket explaining what you learned:
- How long is the default flask session time currently?
- What is the behaviour of flask if we have a remember-me cookie set but we change the application secret key? Does this cause a login, or a logout?
As a next step, we can implement flask's remember_me option. There are a few items in the ticket that we didn't clarify, which we should have. Sorry about that. Keep in mind these things:
- Use a 1 year timeout, like CatQuest suggested. It would be a good idea to make this explicit in case it changes in flask_login in the future
- Yes, we need to use alternate tokens, as described in the documentation, this means we will need to make a database change and make some changes to the user model
- We will need to disable session cookies on API requests
- We don't need a checkbox letting the user select to use 'remember me', instead we should always use this setting. This will keep the login process simple.
As a side note, this is a good place to suggest that if you're unsure about what changes to make, you're absolutely welcome to add a comment to an open ticket asking questions, or telling us what you plan to do. This way we can give feedback before you start.
Please have a look at the initial questions that I mentioned above and see if you can answer them. Once this is done we can continue with the next steps to implement this functionality.
Thanks again for your contributions!
Hello @alastair I have added comments to the ticket. Please have a look:) Wouldn't it be good if we keep the remember me checkbox? Some users might wish to be remembered and some might not :) Thank you. |
Hello @alastair I implemented alternate id, making changes in database and other files. Everything is working fine on localhost, when I change alternate id I get logged out otherwise the session is restored according to remember me cookie. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can have a better name for the alt_id
column, maybe something that describes how we're using it in the login process.
admin/sql/create_tables.sql
Outdated
@@ -12,6 +12,7 @@ CREATE TABLE "user" ( | |||
); | |||
ALTER TABLE "user" ADD CONSTRAINT user_musicbrainz_id_key UNIQUE (musicbrainz_id); | |||
ALTER TABLE "user" ADD CONSTRAINT user_musicbrainz_row_id_key UNIQUE (musicbrainz_row_id); | |||
ALTER TABLE "user" ADD COLUMN alt_id VARCHAR; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@vansika, the bug seems to be here, you're declaring the alt_id
column as varchar, but then comparing it with integers later.
Also, this column should be inside the CREATE TABLE
statement instead of being a seperate ALTER
statement.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please note that the automated tests on travis do a fresh build of the code you push, while your local environment may be different because of experimentation etc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@paramsingh, get_id( ) passes alt_id to load_user( ) which is a string, but the redirects in tests are passing user_id to load_user( ), which is the cause of error because the check function (filter_by_alt_id( )) inside load_user( ) can return user by checking against alt_id (string) and not user_id (integer).
I will try to debug. Thank you
listenbrainz/config.py.sample
Outdated
@@ -117,3 +117,6 @@ SPOTIFY_CALLBACK_URL = 'http://localhost/profile/connect-spotify/callback' | |||
# We do not use this feature at all, so it is safe to set to False. | |||
# See https://stackoverflow.com/a/33790196 for more details. | |||
SQLALCHEMY_TRACK_MODIFICATIONS = False | |||
|
|||
# expiration of 'Remember me' cookie | |||
days = 365 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This name can be more descriptive. SESSION_REMEMBER_ME_DURATION
maybe.
listenbrainz/db/user.py
Outdated
WHERE alt_id = :alt_id | ||
""".format(columns=','.join(USER_GET_COLUMNS))), {"alt_id": alt_id}) | ||
row = result.fetchone() | ||
print (row) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This print can probably be removed.
@@ -29,7 +30,7 @@ def musicbrainz_post(): | |||
if provider.validate_post_login(): | |||
user = provider.get_user() | |||
db_user.update_last_login(user.musicbrainz_id) | |||
login_user(user) | |||
login_user(user, remember=True, duration=datetime.timedelta(days=config.days)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please use current_app.config['days']
here instead of importing config explicitly.
listenbrainz/config.py.sample
Outdated
@@ -98,7 +98,7 @@ MAX_CONTENT_LENGTH = 16 * 1024 * 1024 # 16MB | |||
UPLOAD_FOLDER = "/tmp/lastfm-backup-upload" | |||
|
|||
|
|||
API_URL = 'https://api.listenbrainz.org' | |||
API_URL = 'http://localhost' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this change isn't needed, in my opinion
Also, we try to do descriptive commit messages in comparison to |
1c03d66
to
c985f70
Compare
@alastair |
admin/sql/create_tables.sql
Outdated
@@ -12,6 +12,7 @@ CREATE TABLE "user" ( | |||
); | |||
ALTER TABLE "user" ADD CONSTRAINT user_musicbrainz_id_key UNIQUE (musicbrainz_id); | |||
ALTER TABLE "user" ADD CONSTRAINT user_musicbrainz_row_id_key UNIQUE (musicbrainz_row_id); | |||
ALTER TABLE "user" ADD COLUMN user_login_id VARCHAR; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this column should be added inside the create table function call instead of creating the table and then altering it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, it should be NOT NULL
, I guess.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, If the only thing we're filling this column with is UUIDs, we should use the postgres uuid data type instead. (https://www.postgresql.org/docs/9.6/datatype-uuid.html)
This would make it more efficient. And you could set a default value for all users as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"uuid-ossp" extension is not being created due to some missing files. I will try to fix it and then would use UUID and postgres functions to generate user_login_id.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems that docker entry point need environment variables,defining them results in other authentication problems. Could you help find a way?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've fixed the problem in #479. Thanks for the bug report! As soon as it gets merged, you can rebase this PR and everything should work fine. In the meanwhile, you can just install the extension in your "listenbrainz" db and continue.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
merged now. =)
BEGIN; | ||
|
||
-- Add column for alternative user id for login purpose to user table | ||
ALTER TABLE "user" ADD COLUMN user_login_id VARCHAR; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we will need this script to fill out the column for existing users also, because each user must have a login ID, no matter what.
listenbrainz/db/user.py
Outdated
"""Get user with a specified login ID. | ||
|
||
Args: | ||
id (int): login ID of a user. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should be updated because login ID of the user isn't an integer.
From the documentation, https://flask-login.readthedocs.io/en/latest/#disabling-session-cookie-for-apis, this step only appears to be necessary if we use |
@alastair |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💯
😊 |
@login_forbidden | ||
def musicbrainz(): | ||
if request.method == 'POST': | ||
if 'check' in request.form: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could re-write this to
session['check'] in request.form
That would be more pythonic. :)
session.clear() | ||
logout_user() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm curious, why this change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Session variables need to be cleared before logging out so that remember me cookie is deleted. Otherwise, user won't be able to log out.
self.assertIn('Your Listens', data) | ||
mock_user_get.assert_called_with(user['user_login_id']) | ||
|
||
self.assertIn('My Listens', data) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We've changed "Your Listens" to "My listens", so the "Your Listens" are no longer needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay
BEGIN; | ||
|
||
-- Add column for alternative user id for login purpose to user table | ||
ALTER TABLE "user" ADD COLUMN user_login_id UUID NOT NULL DEFAULT uuid_generate_v4(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just noticed that there's no index on this field, there should be if we use it for lookups
Problem
Some users note that they get logged out of ListenBrainz quite often.
Solution
Introduced a 'Remember me' checkbox and linked it with 'Sign in with Musicbrainz' button. Created a form to send checkbox data to server. If the checkbox is checked then the user will be logged in for specified duration even if the browser is accidentally closed.
Have cleared session before logging out to clear the 'Remember me' token that hinders signing out.