Ejemplo n.º 1
0
def save_story():    
    if current_user is not None and current_user.admin == True:
        story_id = request.form['story_id']
        story_data = json.loads(request.form['story_data'])
        confirm_save = request.form['confirm_save'] != 'false'
        live_story_id = db.collection('application_states').document('application_state').get().get('active_story_id')
        
        print(story_id)

        stories = db.collection('stories')
        for doc in list(stories.list_documents()):
            doc = doc.id
            loop_name = stories.document(doc).get().get('story_name')
            loop_id = stories.document(doc).get().get('story_id')
            if loop_name == story_data['story_name'] and loop_id != story_id:
                # Attempting to save something with a duplicate name
                msg = 'Attempted to save engine with name already used by engine with ID ' + loop_id + '. To save, change current story name or overwrite existing engine with ID'
                return {'success': False, 'retry': False, 'msg': msg}, 200, {'ContentType': 'application/json'}

        if not confirm_save:
            if story_id == live_story_id:
                return {'success': False, 'retry': False, 
                    'msg': 'Attempted to overwrite live enine. Duplicate engine and try saving again.'}, 200, {'ContentType': 'application/json'}
                # return {'success': False, 'rename': False}, 200, {'ContentType': 'application/json'}
            elif stories.document(story_id).get().exists:
                return {'success': False, 'retry': True,
                    'msg': 'You are about to overwrite an existing engine. Are you sure you want to overwrite? If not, try saving with a different engine ID'}, 200, {'ContentType': 'application/json'}
                # return {'success': False, 'rename': True}, 200, {'ContentType': 'application/json'}

        if stories.document(story_id).get().exists:
            stories.document(story_id).update(story_data)
        else:
            stories.document(story_id).set(story_data)

    return {'success': True, 'retry': False, 'msg': 'Story successfully saved'}, 200, {'ContentType': 'application/json'}
Ejemplo n.º 2
0
    def save(self):
        """save()
        Saves the UserActivity object to the Firestore database
        """

        # Gets the document containing the user activity
        activity_doc = db.collection(UserActivity.__collection_name).where(
            'user_id', '==', self.user_id).get()

        # If the user activity already has a document, updates the values
        if activity_doc:
            activity_ref = db.collection(
                UserActivity.__collection_name).document(activity_doc[0].id)
            activity_ref.update({
                'user_id': self.user_id,
                'story_activity': self.story_activity
            })

        # If the user activity does not already have a document, creates a new document
        else:
            db.collection(UserActivity.__collection_name).add({
                'user_id':
                self.user_id,
                'story_activity':
                self.story_activity
            })
Ejemplo n.º 3
0
    def save(self):
        """save()
        Saves the Session object to the Firestore database
        """

        # Gets the document containing the session
        session_doc = db.collection(Session.__collection_name).where(
            'session_key', '==', self.session_key).get()

        # If the user already has a document, updates the values
        if session_doc:
            session_ref = db.collection(Session.__collection_name).document(
                session_doc[0].id)
            session_ref.update({
                'session_key': self.session_key,
                'user_id': self.user_id
            })

        # If the user does not already have a document, creates a new document
        else:
            db.collection(Session.__collection_name).add({
                'session_key':
                self.session_key,
                'user_id':
                self.user_id
            })
Ejemplo n.º 4
0
def update_live_story():  
    if current_user is not None and current_user.admin == True:
        new_live_story = request.form['new_live_story']        
        live_story_data = {'active_story_id': new_live_story, 
            'active_story_ref': db.collection('stories').document(new_live_story)}

        app_states = db.collection('application_states')
        app_states.document('application_state').update(live_story_data)
    return {'list': new_live_story}, 200
Ejemplo n.º 5
0
    def save(self):
        """save()
        Saves the User object to the Firestore database
        """

        # Gets the document containing the user
        user_doc = db.collection(User.__collection_name).where(
            'email', '==', self.email).get()

        # If the user already has a document, updates the values
        if user_doc:
            user_ref = db.collection(User.__collection_name).document(
                user_doc[0].id)
            user_ref.update({
                'email': self.email,
                'password': self.password,
                'salt': self.salt,
                'first_name': self.first_name,
                'last_name': self.last_name,
                'authenticated': self.authenticated,
                'admin': self.admin,
                'last_activity': self.last_activity,
                'favorites': self.favorites,
                'history': self.history,
                'temp_password': self.temp_password,
                'temp_password_expire': self.temp_password_expire
            })

        # If the user does not already have a document, creates a new document
        else:
            db.collection(User.__collection_name).add({
                'email':
                self.email,
                'password':
                self.password,
                'salt':
                self.salt,
                'first_name':
                self.first_name,
                'last_name':
                self.last_name,
                'authenticated':
                self.authenticated,
                'admin':
                self.admin,
                'last_activity':
                self.last_activity,
                'favorites':
                self.favorites,
                'history':
                self.history,
                'temp_password':
                self.temp_password,
                'temp_password_expire':
                self.temp_password_expire
            })
Ejemplo n.º 6
0
def delete_engine():
    if current_user is not None and current_user.admin == True:
        live_story = db.collection('application_states').document('application_state').get().get('active_story_id')
        engine_id = request.form['engine_id']
        if engine_id == live_story:
            return {'success': False}, 200
        
        print(engine_id)
        print(db.collection('stories').document(engine_id).get().get('story_name'))
        db.collection('stories').document(engine_id).delete()

        return {'success': True}, 200
Ejemplo n.º 7
0
def view_live_story():
    if current_user is not None and current_user.admin == True:
        app_states = db.collection('application_states')
        # all_stories = [story for story in stories]
        app_state = list(app_states.list_documents())[0]
        live_story = 'NONE'
        try:
            live_story = app_state.get().get('active_story_id')
            story_name = db.collection('stories').document(live_story).get().get('story_name')
        except KeyError:
            print('No Live Story Field')
        return {'story_id': live_story, 'story_name': story_name}, 200
    return None, 200
Ejemplo n.º 8
0
def get_all_stories():
    if current_user is not None and current_user.admin == True:
        stories = db.collection('stories')
        # all_stories = [story for story in stories]
        child_doc = list(stories.list_documents())
        child_doc = [child.id for child in child_doc]
        story_names = []
        for doc in child_doc:
            story_names.append(db.collection('stories').document(doc).get().get('story_name'))
        
        return {'story_id': child_doc, 'story_name': story_names}, 200
    
    return None, 500
Ejemplo n.º 9
0
def favorites():
    """favorites()
    Serves the favorites page with the user's favorites
    Accessed at '/favorites' via a GET request
    Requires that the user is logged in
    """

    # Creates an array of the user's favorites with information about each page
    favorites = []
    for favorite in current_user.favorites:
        # Gets the story the favorite belongs to
        story_ref = db.collection('stories').document(favorite['story'])
        story_doc = story_ref.get()

        # Gets the page data for the favorite
        page = story_doc.get('page_nodes.`' + favorite['page_id'] + '`')

        # Adds the favorite's page name, the favorite's page link, and which history the favorite belongs to
        favorites.insert(0, (page['page_name'], favorite['story'] + "/" +
                             favorite['page_id'], favorite['history_id']))

    # Returns the favorites.html template with the given values
    return render_response(
        render_template('user_pages/favorites.html',
                        first_name=current_user.first_name,
                        favorites=favorites))
Ejemplo n.º 10
0
    def get_session(session_key=None, user_id=None):
        """get_session(session_key=None, user_id=None)
        Retrieves a session based on the query parameters and returns a Session object with the values populated from Firestore
        """

        # Creates a query on the user collection
        query = db.collection(Session.__collection_name)

        # Filters the query by session key, if one is provided
        if session_key:
            query = query.where('session_key', '==', session_key)

        # Filters the query by user ID, if one is provided
        if user_id:
            query = query.where('user_id', '==', user_id)

        # Checks that exactly one session is found. If no sessions are found, we want to return None. If multiple sessions are found,
        # we want to return None to ensure that no one can access a session they are not meant to.
        query = query.get()
        if len(query) != 1:
            return None

        # Creates and returns a Session object with the values from Firestore
        return Session(user_id=query[0].get('user_id'),
                       session_key=query[0].get('session_key'))
Ejemplo n.º 11
0
    def get_user(email=None):
        """get_user(email=None)
        Retrieves a user based on the query parameters and returns a User object with the values populated from Firestore
        """

        # Creates a query on the user collection
        query = db.collection(User.__collection_name)

        # Filters the query by email, if one is provided
        if email:
            query = query.where('email', '==', email)

        # Checks that exactly one user is found. If no users are found, we want to return None. If multiple users are found,
        # we want to return None to ensure that no one can access a user account they are not meant to.
        query = query.get()
        if len(query) != 1:
            return None

        # Creates and returns a User object with the values from Firestore
        return User(email=query[0].get('email'),
                    password=query[0].get('password'),
                    salt=query[0].get('salt'),
                    first_name=query[0].get('first_name'),
                    last_name=query[0].get('last_name'),
                    authenticated=query[0].get('authenticated'),
                    admin=query[0].get('admin'),
                    last_activity=query[0].get('last_activity'),
                    favorites=query[0].get('favorites'),
                    history=query[0].get('history'),
                    temp_password=query[0].get('temp_password'),
                    temp_password_expire=query[0].get('temp_password_expire'))
Ejemplo n.º 12
0
    def get_user_activity(user_id):
        """get_user_activity(user_id=None)
        Retrieves a session based on the query parameters and returns a Session object with the values populated from Firestore
        """

        # Creates a query on the user collection
        query = db.collection(UserActivity.__collection_name)

        # Filters the query by user ID, if one is provided
        if user_id:
            query = query.where('user_id', '==', user_id)

        # Checks that exactly one user activity is found. If no user activities are found, we want to create a new user activity.
        # If multiple user activities are found, we want to return None to ensure that no one can access a user activity they are
        # not meant to.
        query = query.get()
        if len(query) != 1:
            # If no user activities are found, creates a new one
            if len(query) == 0:
                user = UserActivity(user_id=user_id)
                user.save()
                return user
            return None

        # Creates and returns a UserActivity object with the values from Firestore
        return UserActivity(user_id=query[0].get('user_id'),
                            story_activity=query[0].get('story_activity'))
Ejemplo n.º 13
0
def open_story(story_id):
    if current_user is not None and current_user.admin == True:
        story_data = db.collection('stories').document(story_id)
        if story_data.get().exists:
            # return story_data # should return some success code
            # return json.dumps({'success': True}), 200, story_data.get().to_dict()
            return story_data.get().to_dict(), 200
    return None, 500 # should be an error code of some sort
Ejemplo n.º 14
0
def load_all_stories():
    if current_user is not None and current_user.admin == True:
        stories = db.collection('stories')
        # all_stories = [story for story in stories]
        child_doc = list(stories.list_documents())
        child_doc = [child.id for child in child_doc]
        return {'list': child_doc}, 200
    
    return None, 500
Ejemplo n.º 15
0
    def __init__(self, user_id, session_key=None):
        """Session(user_id, session_key=None)
        Creates a new Session object
        """

        self.user_id = user_id

        # Checks if a session key was provided, if not it generates a new one and stores the session in Firestore
        if session_key:
            self.session_key = session_key
        else:
            # Generates a session key
            self.session_key = str(uuid.uuid4())

            # Saves the session to Firestore
            db.collection(Session.__collection_name).add({
                'session_key':
                self.session_key,
                'user_id':
                self.user_id
            })
Ejemplo n.º 16
0
def index():
    """index()
    Serves the home page
    Accessed at '/' via a GET request
    """

    # Checks if the user is logged in
    if current_user:
        # Checks if the user is an admin
        if current_user.admin:
            # Returns the admin homepage
            return render_response(
                render_template('admin_pages/homepage.html',
                                first_name=current_user.first_name))

        # Gets the active engine to link to with the 'Begin Story' button
        begin_story = db.collection('application_states').document(
            'application_state').get().get('active_story_id')

        # Gets the most recent story to link to with the 'Continue Story' button
        most_recent_history = None
        continue_story = None
        # Loops over the stories in the user's history
        for index, history in enumerate(current_user.history):
            # Sets the continue_story to the first story in the user's history
            if most_recent_history is None:
                most_recent_history = index
                continue_story = current_user.history[most_recent_history][
                    'story'] + '/' + current_user.history[most_recent_history][
                        'pages'][-1]

            # Checks if each story was more recently accessed than the current_story; if so, updates the current_story
            elif history['last_updated'].replace(
                    tzinfo=None) > current_user.history[most_recent_history][
                        'last_updated'].replace(tzinfo=None):
                most_recent_history = index
                continue_story = current_user.history[most_recent_history][
                    'story'] + '/' + current_user.history[most_recent_history][
                        'pages'][-1]

        # Returns the user homepage
        return render_response(
            render_template('user_pages/homepage.html',
                            first_name=current_user.first_name,
                            begin_story=begin_story,
                            continue_story=continue_story,
                            history=most_recent_history))

    # Returns the homepage
    return render_response(render_template('home.html'))
Ejemplo n.º 17
0
    def delete_session(session_key=None, user_id=None):
        """delete_session(session_key=None, user_id=None)
        Deletes a session based on the query parameters and returns a Session object with the values populated from Firestore
        """

        # Creates a query on the user collection
        query = db.collection(Session.__collection_name)

        # Filters the query by session key, if one is provided
        if session_key:
            query = query.where('session_key', '==', session_key)

        # Filters the query by user ID, if one is provided
        if user_id:
            query = query.where('user_id', '==', user_id)

        # Checks that exactly one session is found. If no sessions are found, we want to return None. If multiple sessions are found,
        # we want to do nothing so that we don't end a session we don't intend to
        query = query.get()
        if len(query) == 1:
            # Deletes the session from Firestore
            db.collection(Session.__collection_name).document(
                query[0].id).delete()
Ejemplo n.º 18
0
def history():
    """history()
    Serves the history page with the user's history
    Accessed at '/history' via a GET request
    Requires that the user is logged in
    """

    # The current user's history
    history = current_user.history

    # The array with the history information to pass to the history page
    # [[(page_id, history)]]
    history_arr = []

    # Sorts the history
    for i in range(len(history)):
        for j in range(i + 1, len(history)):
            if history[i]['last_updated'].replace(
                    tzinfo=None) < history[j]['last_updated'].replace(
                        tzinfo=None):
                history[i], history[j] = history[j], history[i]

    # Builds the array to pass to the history page
    for hist in history:
        # The array with the history information for this history
        new_arr = []

        # Gets the story the history belongs to
        story_ref = db.collection('stories').document(hist['story'])
        story_doc = story_ref.get()

        # Adds each page in this history to the array
        for page_id in hist['pages']:
            # Gets the page data by page ID
            page = story_doc.get('page_nodes.`' + page_id + '`')

            # Adds the page's name and link
            new_arr.insert(0,
                           (page['page_name'], hist['story'] + "/" + page_id))

        # Appends the
        history_arr.append(new_arr)

    # Returns the history page with the history data
    return render_response(
        render_template('user_pages/history.html', history=history_arr))
Ejemplo n.º 19
0
    def get_all_users():
        """get_all_users()
        Retrieves basic information for all users in Firestore
        Only returns their email, first name, last name, last activity, and admin status
        Does not return sensitive data like password and salt
        """

        users = []

        # Gets an iterator over all users in the user collection in Firestore
        query = db.collection(User.__collection_name).stream()
        for user in query:
            # Adds just the email, first name, last name, last activity, and admin status to the output
            users.append({
                'email': user.get('email'),
                'first_name': user.get('first_name'),
                'last_name': user.get('last_name'),
                'admin': user.get('admin'),
                'last_activity': user.get('last_activity')
            })

        return users
Ejemplo n.º 20
0
    def update_email(self, email):
        """update_email(email)
        Used to update the user's email, since the save function looks for the document to update by email
        """

        # Stores the old email
        old_email = self.email

        # Updates the User object's email field
        self.email = email

        # Gets the document containing the user searching by the old email
        user_doc = db.collection(User.__collection_name).where(
            'email', '==', old_email).get()

        # If the user already has a document, updates the values
        if user_doc:
            user_ref = db.collection(User.__collection_name).document(
                user_doc[0].id)
            user_ref.update({
                'email': self.email,
                'password': self.password,
                'salt': self.salt,
                'first_name': self.first_name,
                'last_name': self.last_name,
                'authenticated': self.authenticated,
                'admin': self.admin,
                'last_activity': self.last_activity,
                'favorites': self.favorites,
                'history': self.history,
                'temp_password': self.temp_password,
                'temp_password_expire': self.temp_password_expire
            })

        # If the user does not already have a document, creates a new document
        else:
            db.collection(User.__collection_name).add({
                'email':
                self.email,
                'password':
                self.password,
                'salt':
                self.salt,
                'first_name':
                self.first_name,
                'last_name':
                self.last_name,
                'authenticated':
                self.authenticated,
                'admin':
                self.admin,
                'last_activity':
                self.last_activity,
                'favorites':
                self.favorites,
                'history':
                self.history,
                'temp_password':
                self.temp_password,
                'temp_password_expire':
                self.temp_password_expire
            })
Ejemplo n.º 21
0
def story_page(story, page_id):
    """story_page()
    Serves a page of a story
    Accessed at '/story/<story/<page_id>' via a GET or POST request
    """

    # Gets the DocumentReference to the story document in Firestore
    story_ref = db.collection('stories').document(story)

    # Gets the DocumentSnapshot of the story document in Firestore
    story_doc = story_ref.get()

    # Checks whether or not the story exists
    if not story_doc.exists:
        abort(404)

    # Checks whether or not the page exists in the story
    if page_id not in story_doc.get('page_nodes'):
        abort(404)

    # Gets the page data for the specified page ID
    page = story_doc.get('page_nodes.`' + page_id + '`')

    # Gets whether or not the page should be displayed as a preview
    preview = request.args.get('preview')
    if preview == None:
        preview = False

    # Gets whether or not the user is a guest
    guest = current_user == None

    # Replaces user attributes in the page content with the current user's values
    for user_attr in allowed_user_attr:
        page['page_body_text'] = page['page_body_text'].replace('$$' + user_attr + '$$', 'Guest' if guest else getattr(current_user, user_attr))

    # Gets whether or not the page is favorited
    favorited = False
    if not guest:
        for favorite in current_user.favorites:
            if favorite['story'] == story and favorite['page_id'] == page_id:
                favorited = True

    ###############################################################################################################
    # In order to log a user's history, each time they click a link when navigating a story we include the        #
    # previous page, an ID for which history they are on (so if they have taken multiple paths through the        #
    # story, which index in the database corresponds to the current one), and whether or not they are navigating  #
    # forward or backwards. If a request to a story page comes from one of the ways we intend (homepage, history, #
    # favorites, another story page), then it will be formed as a POST request with these fields so that we know  #
    # exactly what the user is doing. If the user reaches the page through another means (most likely copying and #
    # pasting the URL, i.e. a GET request), then we will treat this as the user starting a new history from       #
    # whichever page they go to, since we don't have a history to tie this to.                                    #
    ###############################################################################################################

    # Checks that the request comes as a POST request and includes the information for recording user history
    if request.method == 'POST':
        prev_page_id = request.form['prev_page_id']
        history_id = request.form['history_id']
        forward = request.form['forward']
        back = prev_page_id

        # Checks that the user is logged in
        if not guest:
            # Records the page visit to story activity
            user_activity = UserActivity.get_user_activity(current_user.email)
            user_activity.story_activity.append({
                'timestamp': datetime.now(),
                'story': story,
                'page_id': page_id
                })
            user_activity.save()

            # Checks if a history ID is included, if not a new history is added
            if history_id == '':
                # Checks for a matching history, to not add a duplicate history
                history_found = False
                for index, history in enumerate(current_user.history):
                    if history['story'] == story and history['pages'][0] == page_id and len(history['pages']) == 1:
                        history['last_updated'] = datetime.now()
                        history_found = True
                        history_id = index

                # If a matching history does not already exists, adds the root page to a new history
                if not history_found:
                    new_history = {}
                    new_history['last_updated'] = datetime.now()
                    new_history['story'] = story
                    new_history['pages'] = [page_id]
                    current_user.history.append(new_history)
                    history_id = len(current_user.history) - 1

                # Saves the changes to the user
                current_user.save()

            # If a history ID is include, we will edit it according to the user's behavior
            else:
                history_id = int(history_id)
                history = current_user.history[history_id]

                # If the user is moving forwards
                if forward:
                    # Checks if the current page is already included in the history, if not it is added
                    if page_id not in current_user.history[history_id]['pages']:
                        # Checks if the previous page the user visited is the last page recorded in the current history
                        if prev_page_id == current_user.history[history_id]['pages'][-1]:
                            # Appends the current page to the current history and updates the timestamp
                            current_user.history[history_id]['pages'].append(page_id)
                            current_user.history[history_id]['last_updated'] = datetime.now()

                        # If the previous page is not the last page recorded, then the user is branching off from their previous
                        # path, making a new decision. In this case, we want to copy the path up to the point of the previous page
                        # and add the current page
                        else:
                            new_history = {}
                            new_history['pages'] = []
                            for p in current_user.history[history_id]['pages']:
                                new_history['pages'].append(p)
                                if p == prev_page_id:
                                    break
                            new_history['pages'].append(page_id)
                            new_history['story'] = current_user.history[history_id]['story']
                            new_history['last_updated'] = datetime.now()
                            current_user.history.append(new_history)
                            history_id = len(current_user.history) - 1

                        # Checks that the history updated or the new history created does not match another history. If there is one,
                        # removes the current history and switches to the matching one that already existed
                        for index, h1 in enumerate(current_user.history):
                            for h2 in current_user.history:
                                if h1 != h2 and len(h1['pages']) == len(h2['pages']):
                                    history_matches = True
                                    for p in range(len(h1['pages'])):
                                        if h1['pages'][p] != h2['pages'][p]:
                                            history_matches = False
                                    if history_matches:
                                        current_user.history.remove(h2)
                                        h1['last_updated'] = datetime.now()
                                        history_id = index

                    # If the history already contains the current page, we can just update the timestamp, but
                    # we don't want to add a duplicate page ID
                    else:
                        current_user.history[history_id]['last_updated'] = datetime.now()

                    # Saves the changes to the user
                    current_user.save()

                # If the user is moving backwards
                else:
                    # Add any behavior for backwards navigation here
                    pass

                # Sets the back page to the previous page in the history
                back = None
                back_name = None
                for p in current_user.history[history_id]['pages']:
                    if p == page_id:
                        break
                    back = p
                    # Gets the page name of the page that the back button points to
                    back_name = story_doc.get('page_nodes.`' + back + '`')['page_name']

        # Returns the story_page.html template with the specified page
        return render_response(render_template("story_page.html", guest=guest, favorited=favorited, story=story, page=page, preview=preview, back=back, back_name=back_name, history=history_id))

    # Checks that the user is logged in and not previewing the page
    # Adds a new history in case the user gets to this page from an external link that wouldn't include the information to append the page to a history
    if not preview and not guest:
        # Checks for a matching history, to not add a duplicate history
        history_found = False
        for history in current_user.history:
            if history['story'] == story and history['pages'][0] == page_id and len(history['pages']) == 1:
                history['last_updated'] = datetime.now()
                history_found = True

        # If a matching history does not already exists, adds the root page to a new history
        if not history_found:
            new_history = {}
            new_history['last_updated'] = datetime.now()
            new_history['story'] = story
            new_history['pages'] = [page_id]
            current_user.history.append(new_history)

        # Saves the changes to the user
        current_user.save()

    # Returns the story_page.html template with the specified page
    return render_response(render_template("story_page.html", guest=guest, favorited=favorited, story=story, page=page, preview=preview))
Ejemplo n.º 22
0
def story_root(story):
    """story_root()
    Serves the root page of a story
    Accessed at '/story/<story' via a GET request
    """

    # Gets the DocumentReference to the story document in Firestore
    story_ref = db.collection('stories').document(story)

    # Gets the DocumentSnapshot of the story document in Firestore
    story_doc = story_ref.get()

    # Checks whether or not the story exists
    if not story_doc.exists:
        abort(404)

    # Gets the root page's page ID
    page_id = story_doc.get('root_id')

    # Gets the page data for the specified page ID
    page = story_doc.get('page_nodes.`' + page_id + '`')

    # Gets whether or not the page is viewed as a preview (from history page)
    preview = request.args.get('preview')
    if preview == None:
        preview = False

    # Gets whether or not the user is logged in
    guest = current_user == None

    # Replaces user attributes in the page content with the current user's values
    for user_attr in allowed_user_attr:
        page['page_body_text'] = page['page_body_text'].replace('$$' + user_attr + '$$', 'Guest' if guest else getattr(current_user, user_attr))

    history_id = None
    if not preview and not guest:
        # Records the page visit to story activity
        user_activity = UserActivity.get_user_activity(current_user.email)
        user_activity.story_activity.append({
            'timestamp': datetime.now(),
            'story': story,
            'page_id': page_id
            })
        user_activity.save()

        # Checks for a matching history, to not add a duplicate history
        history_found = False
        for index, history in enumerate(current_user.history):
            if history['story'] == story and history['pages'][0] == page_id and len(history['pages']) == 1:
                # Updates timestamp of matching history
                history['last_updated'] = datetime.now()
                history_found = True
                history_id = index

        # If a matching history does not already exists, adds the root page to a new history
        if not history_found:
            new_history = {}
            new_history['last_updated'] = datetime.now()
            new_history['story'] = story
            new_history['pages'] = [page_id]
            current_user.history.append(new_history)
            history_id = len(current_user.history) - 1

        # Saves the changes to the user
        current_user.save()

    # Gets whether or not the page is favorited
    favorited = False
    if not guest:
        for favorite in current_user.favorites:
            if favorite['story'] == story and favorite['page_id'] == page_id:
                favorited = True

    # Returns the story_page.html template with the specified page
    return render_response(render_template('story_page.html', guest=guest, favorited=favorited, story=story, page=page, preview=preview, history=history_id))