diff --git a/applications/home/urls.py b/applications/home/urls.py index 2cabddce..7eb62b80 100644 --- a/applications/home/urls.py +++ b/applications/home/urls.py @@ -14,4 +14,5 @@ url(r'^about_us/$', views.about_us_page, name='about_us'), url(r'^forgot_password/$', views.forgot_password_page, name='forgot_password'), url(r'^reset_password/$', views.reset_password_page, name='reset_password'), + url(r'^account/$', views.account_page, name='account'), ] diff --git a/applications/home/views.py b/applications/home/views.py index d9ddf1a0..3359d23a 100644 --- a/applications/home/views.py +++ b/applications/home/views.py @@ -1,4 +1,5 @@ import json + from applications.users.forms import RegisterForm from django.http import HttpResponse, HttpResponseRedirect from django.shortcuts import render, redirect @@ -7,6 +8,11 @@ from graphspace.utils import * from graphspace.exceptions import * +# import the logging library +import logging + +# Get an instance of a logger +logger = logging.getLogger(__name__) def home_page(request): """ @@ -157,7 +163,7 @@ def forgot_password_page(request): return render(request, 'forgot_password/index.html', context) # Handle GET request to forgot password page. elif 'POST' == request.method: password_reset_code = users.add_user_to_password_reset(request, email=request.POST.get('forgot_email', None)) - + logger.error(password_reset_code) if password_reset_code is not None: users.send_password_reset_email(request, password_reset_code) context["success_message"] = "Email has been sent!" @@ -218,7 +224,6 @@ def reset_password_page(request): def login(request): """ Handles login (POST) request. - :param request: HTTP Request """ if 'POST' == request.method: @@ -290,4 +295,43 @@ def images(request, query): :param request: HTTP GET Request """ - return redirect('/static' + request.path) \ No newline at end of file + return redirect('/static' + request.path) + + +def account_page(request): + """ + Wrapper view function for the following pages: + / + account/index.html + + Parameters + ---------- + request : HTTP Request + + Returns + ------- + response : HTML Page Response + Rendered account home page in HTML. + + Raises + ------ + MethodNotAllowed: If a user tries to send requests other than GET i.e., POST, PUT or UPDATE. + + Notes + ------ + + """ + context = RequestContext(request) # Checkout base.py file to see what context processors are being applied here. + + if 'GET' == request.method: + auth_token = users.get_auth_token(request, request.session['uid']) + logger.error(auth_token) + if auth_token is None: + context['error_message'] = "Please try logging in again." + else: + context['auth_token'] = auth_token + return render(request, 'account/index.html', context) # Handle GET request to auth_token page. + else: + raise MethodNotAllowed(request) # Handle other type of request methods like POST, PUT, UPDATE. + + diff --git a/applications/users/controllers.py b/applications/users/controllers.py index be2fe623..2baa4eea 100644 --- a/applications/users/controllers.py +++ b/applications/users/controllers.py @@ -1,4 +1,5 @@ import bcrypt +import base64 from django.conf import settings from django.core.mail import send_mail @@ -26,11 +27,15 @@ def authenticate_user(request, username=None, password=None): #check password. if the password matches, return a #User object with associated information if bcrypt.hashpw(password, hashed_pw) == hashed_pw: + #Check auth_token in database. If it is None, create and save new auth_token to database. + if user.auth_token == None: + user = update_user(request, user.id, email=user.email, password=password) return { 'id': user.id, 'user_id': user.email, 'password': user.password, - 'admin': user.is_admin + 'admin': user.is_admin, + 'auth_token': user.auth_token } else: return None @@ -40,11 +45,12 @@ def update_user(request, user_id, email=None, password=None, is_admin=None): user = {} if email is not None: user['email'] = email + user['auth_token'] = 'Basic %s' % base64.b64encode('{0}:{1}'.format(email, password)) if password is not None: user['password'] = bcrypt.hashpw(password, bcrypt.gensalt()) + user['auth_token'] = 'Basic %s' % base64.b64encode('{0}:{1}'.format(email, password)) if is_admin is not None: user['is_admin'] = is_admin - return db.update_user(request.db_session, id=user_id, updated_user=user) @@ -129,11 +135,12 @@ def search_users(request, email=None, limit=20, offset=0, order='desc', sort='na def register(request, username=None, password=None): if db.get_user(request.db_session, username): raise BadRequest(request, error_code=ErrorCodes.Validation.UserAlreadyExists, args=username) + auth_token = 'Basic %s' % base64.b64encode('{0}:{1}'.format(username, password)) - return add_user(request, email=username, password=password) + return add_user(request, email=username, password=password, auth_token=auth_token) -def add_user(request, email=None, password="graphspace_public_user", is_admin=0): +def add_user(request, email=None, password="graphspace_public_user", auth_token=None, is_admin=0): """ Add a new user. If email and password is not passed, it will create a user with default values. By default a user has no admin access. @@ -142,11 +149,12 @@ def add_user(request, email=None, password="graphspace_public_user", is_admin=0) :param email: User ID of the user. Default value is dynamically generated user id. :param password: Password of the user. Default value is "public". :param admin: 1 if user has admin access else 0. Default value is 0. + :param auth_token: Auth_token if the user. Default value is None. :return: User """ email = "public_user_%s@graphspace.com" % generate_uid(size=10) if email is None else email - return db.add_user(request.db_session, email=email, password=bcrypt.hashpw(password, bcrypt.gensalt()), is_admin=is_admin) + return db.add_user(request.db_session, email=email, password=bcrypt.hashpw(password, bcrypt.gensalt()), auth_token=auth_token, is_admin=is_admin) def is_member_of_group(request, username, group_id): @@ -312,3 +320,13 @@ def send_password_reset_email(request, password_reset_code): email_from = "GraphSpace Admin" return send_mail(mail_title, message, email_from, [password_reset_code.email], fail_silently=False) + +def get_auth_token(request, email): + # check the username and return a User + user = db.get_user(request.db_session, email) + + if user: + return user.auth_token + else: + return None + diff --git a/applications/users/dal.py b/applications/users/dal.py index 66b19861..f62e565b 100644 --- a/applications/users/dal.py +++ b/applications/users/dal.py @@ -7,12 +7,16 @@ from graphspace.wrappers import with_session from models import * +import logging + +# Get an instance of a logger +logger = logging.getLogger(__name__) # TODO: Add documentation about exception raised. @with_session -def add_user(db_session, email, password, is_admin): +def add_user(db_session, email, password, auth_token, is_admin): """ Add a new user. @@ -20,9 +24,10 @@ def add_user(db_session, email, password, is_admin): :param email: User ID of the user. :param password: Password of the user. :param admin: 1 if user has admin access else 0. + :param auth_token: Auth_token of the user. :return: User """ - user = User(email=email, password=password, is_admin = is_admin) + user = User(email=email, password=password, auth_token=auth_token, is_admin=is_admin) db_session.add(user) return user @@ -322,3 +327,14 @@ def find_groups(db_session, owner_email, member_email, name, description, graph_ query = query.limit(limit).offset(offset) return total, query.all() + +@with_session +def get_auth_token(db_session, email): + """ + Get the auth_token with given email. + + :param db_session: Database session. + :param email: email of the user. + :return: User's auth_token if email exists else None. + """ + return db_session.query().filter(User.email == email).one_or_none() diff --git a/applications/users/models.py b/applications/users/models.py index 053fc6f1..1cb66545 100644 --- a/applications/users/models.py +++ b/applications/users/models.py @@ -17,12 +17,14 @@ class User(IDMixin, TimeStampMixin, Base): :param email: Email ID of the user. :param password: Password of the user. :param admin: 1 if the user has admin access else 0. + :param auth_token: Auth_token of the user. """ __tablename__ = "user" email = Column(String, nullable=False, unique=True, index=True) password = Column(String, nullable=False) is_admin = Column(Integer, nullable=False, default=0) + auth_token = Column(String, nullable=True) password_reset_codes = relationship("PasswordResetCode", back_populates="user", cascade="all, delete-orphan") owned_groups = relationship("Group", back_populates="owner", cascade="all, delete-orphan") diff --git a/docs/Programmers_Guide.md b/docs/Programmers_Guide.md index f2434b9d..8b7443e4 100644 --- a/docs/Programmers_Guide.md +++ b/docs/Programmers_Guide.md @@ -34,6 +34,34 @@ The GraphSpace REST API is served over HTTP. In case you are +## API Authentication Token +### Obtain Authentication Token +To get your API authentication token, log into your GraphSpace account and navigate to your account page. Once you are there click on the **Authentication Token** tab on the top. Then you can see your authentication token value. + + + +### Use Authentication Token to Access GraphSpace API +cURL is the most used command line tool for making API calls. Here we use cURL command as an example. + +**GET** +``` +curl -X GET \ + '**YOUR GRAPHSPACE API URL**' \ + -H 'accept: application/json' \ + -H 'authorization: Basic **YOUR API AUTH TOKEN**' \ + -H 'content-type: application/json' \ +``` +**POST** +``` +curl -X POST \ + **YOUR GRAPHSPACE API URL** \ + -H 'accept: application/json' \ + -H 'authorization: Basic **YOUR API AUTH TOKEN**' \ + -H 'content-type: application/json' \ + -d '**YOUR JSON DATA**' +``` + + ## graphspace-python diff --git a/static/js/account_page.js b/static/js/account_page.js new file mode 100644 index 00000000..b3eac968 --- /dev/null +++ b/static/js/account_page.js @@ -0,0 +1,10 @@ +var accountPage = { + init: function () { + /** + * This function is called to setup the account page. + * It will initialize all the event listeners. + */ + utils.initializeTabs(); + + }, +} diff --git a/templates/404.html b/templates/404.html index a564e7bf..e127f589 100644 --- a/templates/404.html +++ b/templates/404.html @@ -16,11 +16,11 @@