diff --git a/bbcli/cli.py b/bbcli/cli.py
index 4f6afff1eb42ed8e87399a3d92331d21ea29c155..6faabf7da09c271e0dcaa705dd067cc04a0d4307 100644
--- a/bbcli/cli.py
+++ b/bbcli/cli.py
@@ -17,7 +17,6 @@ def entry_point():
     pass
 
 
-
 entry_point.add_command(get_user)
 entry_point.add_command(get_course_contents)
 entry_point.add_command(get_assignments)
diff --git a/bbcli/controllers/announcement_controller.py b/bbcli/controllers/announcement_controller.py
new file mode 100644
index 0000000000000000000000000000000000000000..c43810c9611b288d90adfa19460609a4087b13f5
--- /dev/null
+++ b/bbcli/controllers/announcement_controller.py
@@ -0,0 +1,41 @@
+from email.policy import default
+import click
+from bbcli.services import announcement_service
+from bbcli.views import announcement_view
+import os
+import requests
+
+from bbcli.utils.utils import set_cookies, set_headers
+
+@click.command(name='announcements')
+@click.argument('course_id', required=False)
+@click.argument('announcement_id', required=False)
+def list_announcements(course_id=None, announcement_id=None):
+
+    """
+    This command lists your announcements.
+    Either all announcements, all announcements from a spesific course, or one announcement.
+    """
+
+    bb_cookie = {
+        'name':'BbRouter',
+        'value': os.getenv("BB_ROUTER")
+    }
+    xsrf = {'X-Blackboard-XSRF': os.getenv('XSRF')}
+    user_name = os.getenv('BB_USERNAME')
+
+    session = requests.Session()
+    set_cookies(session, [bb_cookie])
+    set_headers(session, [xsrf])
+
+    response = None
+    
+    if announcement_id:
+        response = announcement_service.list_announcement(session, course_id, announcement_id)
+        announcement_view.print_course_announcements([response])
+    elif course_id:
+        response = announcement_service.list_course_announcements(session, course_id)
+        announcement_view.print_course_announcements(response)
+    else:
+        response = announcement_service.list_announcements(session, user_name)
+        announcement_view.print_announcements(response)
diff --git a/bbcli/controllers/course_controller.py b/bbcli/controllers/course_controller.py
new file mode 100644
index 0000000000000000000000000000000000000000..9a919341c20b031cf4d4d03c7f9f83bb92510c78
--- /dev/null
+++ b/bbcli/controllers/course_controller.py
@@ -0,0 +1,41 @@
+from email.policy import default
+import click
+from bbcli.services import course_service
+from bbcli.views import course_view
+import os
+import requests
+from bbcli.utils.utils import set_cookies, set_headers
+
+
+#, help='List a spesific course with the corresponding id'
+@click.command(name='courses')
+@click.argument('course_id', required=False)
+@click.option('-a', '--all/--no-all', 'show_all', default=False, help='Lists all courses you have ever been signed up for')
+def list_courses(course_id=None, show_all=False):
+
+    """
+    This command lists your courses, by default only the courses from
+    two last semesters
+    """
+
+    bb_cookie = {
+        'name':'BbRouter',
+        'value': os.getenv("BB_ROUTER")
+    }
+    user_name = os.getenv('BB_USERNAME')
+
+    session = requests.Session()
+    set_cookies(session, [bb_cookie])
+
+    response = None
+    
+    if course_id:
+        response = course_service.list_course(session=session, course_id=course_id)
+        course_view.print_course(response)
+    else:
+        if show_all:
+            response = course_service.list_all_courses(session=session, user_name=user_name)
+        else:
+            response = course_service.list_courses(session=session, user_name=user_name)
+        course_view.print_courses(response)
+
diff --git a/bbcli/services/ContentService.py b/bbcli/services/ContentService.py
deleted file mode 100644
index b28b04f643122b019e912540f228c8ed20be9eeb..0000000000000000000000000000000000000000
--- a/bbcli/services/ContentService.py
+++ /dev/null
@@ -1,3 +0,0 @@
-
-
-
diff --git a/bbcli/services/__init__.py b/bbcli/services/__init__.py
index 540e4cbbe654d8299db8737108ad2ac292234b79..f30c4e42d3b55b2e31bb4a281935a9f0513de3f0 100644
--- a/bbcli/services/__init__.py
+++ b/bbcli/services/__init__.py
@@ -1 +1,2 @@
-from .authorization_service import *
\ No newline at end of file
+from .authorization_service import *
+from bbcli.utils.URL_builder import URLBuilder
\ No newline at end of file
diff --git a/bbcli/services/announcement_service.py b/bbcli/services/announcement_service.py
index 90177768b8a4ab591f54d25baec9d2e7c098df59..2de1420d927df92fb927c342a9a5d2e2d3e0b225 100644
--- a/bbcli/services/announcement_service.py
+++ b/bbcli/services/announcement_service.py
@@ -3,16 +3,20 @@ from subprocess import call
 from typing import Dict, Any
 import requests
 from bbcli.services.course_service import list_courses
+from bbcli.utils.utils import set_cookies
 import click
 
-def list_announcements(cookies: Dict, user_name: str):
-    courses = list_courses(cookies=cookies, user_name=user_name)
+from bbcli.utils.URL_builder import URLBuilder
 
-    session = requests.Session()
+url_builder = URLBuilder()
+
+def list_announcements(session: requests.Session, user_name: str):
+    courses = list_courses(session, user_name=user_name)
     announcements = []
 
     for course in courses:
-        course_announcements = session.get('https://ntnu.blackboard.com/learn/api/public/v1/courses/{}/announcements'.format(course['id']), cookies=cookies)
+        url = url_builder.base_v1().add_courses().add_id(course['id']).add_announcements().create()
+        course_announcements = session.get(url)
         course_announcements = json.loads(course_announcements.text)
         
         # Adds the course name to each course announcement list to make it easier to display which course the announcement comes from
@@ -24,19 +28,21 @@ def list_announcements(cookies: Dict, user_name: str):
     
     return announcements
 
-def list_course_announcements(cookies: Dict, course_id: str):
-    course_announcements = requests.get('https://ntnu.blackboard.com/learn/api/public/v1/courses/{}/announcements'.format(course_id), cookies=cookies)
+def list_course_announcements(session: requests.Session, course_id: str):
+    url = url_builder.base_v1().add_courses().add_id(course_id).add_announcements().create()
+    course_announcements = session.get(url)
+    course_announcements.raise_for_status()
     course_announcements = json.loads(course_announcements.text)['results']
     return course_announcements
 
-def list_announcement(cookies: Dict, course_id: str, announcement_id: str):
-    announcement = requests.get('https://ntnu.blackboard.com/learn/api/public/v1/courses/{}/announcements/{}'.format(course_id, announcement_id), cookies=cookies)
+def list_announcement(session: requests.Session, course_id: str, announcement_id: str):
+    url = url_builder.base_v1().add_courses().add_id(course_id).add_announcements().add_id(announcement_id).create()
+    announcement = session.get(url)
     announcement = json.loads(announcement.text)
     return announcement
 
 # TODO: Add compatibility for flags and options to make a more detailed announcement
-def create_announcement(cookies: Dict, headers: Dict, course_id: str, title: str):
-    
+def create_announcement(session: requests.Session, course_id: str, title: str):
     MARKER = '# Everything below is ignored\n'
     body = click.edit('\n\n' + MARKER)
     if body is not None:
@@ -48,22 +54,24 @@ def create_announcement(cookies: Dict, headers: Dict, course_id: str, title: str
     }
 
     data = json.dumps(data)
-    headers['Content-Type'] = 'application/json'
+    session.headers.update({'Content-Type': 'application/json'})
 
-    response = requests.post('https://ntnu.blackboard.com/learn/api/public/v1/courses/{}/announcements'.format(course_id), cookies=cookies, headers=headers, data=data)
+    url = url_builder.base_v1().add_courses().add_id(course_id).add_announcements().create()
+    response = session.post(url, data=data)
 
     return response.text
 
-def delete_announcement(cookies: Dict, headers: Dict, course_id: str, announcement_id: str):
-    response = requests.delete('https://ntnu.blackboard.com/learn/api/public/v1/courses/{}/announcements/{}'.format(course_id, announcement_id), cookies=cookies, headers=headers)
+def delete_announcement(session: requests.Session, course_id: str, announcement_id: str):
+    url = url_builder.base_v1().add_courses().add_id(course_id).add_announcements().add_id(announcement_id).create()
+    response = session.delete(url)
     if response.text == '':
         return 'Sucessfully deleted announcement!'
     else:
         return response.text
 
-def update_announcement(cookies: Dict, headers: Dict, course_id: str, announcement_id: str):
+def update_announcement(session: requests.Session, course_id: str, announcement_id: str):
 
-    announcement = list_announcement(cookies=cookies, course_id=course_id, announcement_id=announcement_id)
+    announcement = list_announcement(session=session, course_id=course_id, announcement_id=announcement_id)
     MARKER = '# Everything below is ignored\n'
     editable_data = {
         'title': announcement['title'],
@@ -75,7 +83,9 @@ def update_announcement(cookies: Dict, headers: Dict, course_id: str, announceme
     announcement = json.dumps(editable_data, indent=2)
     new_data = click.edit(announcement + '\n\n' + MARKER)
 
-    headers['Content-Type'] = 'application/json'
-    response = requests.patch('https://ntnu.blackboard.com/learn/api/public/v1/courses/{}/announcements/{}'.format(course_id, announcement_id), cookies=cookies, headers=headers, data=new_data)
+    session.headers.update({'Content-Type': 'application/json'})
+
+    url = url_builder.base_v1().add_courses().add_id(course_id).add_announcements().add_id(announcement_id).create()
+    response = session.patch(url, data=new_data)
 
     return response.text
\ No newline at end of file
diff --git a/bbcli/services/authorization_service.py b/bbcli/services/authorization_service.py
index 71e5de6f0cb99d0bda0f123c34dd76efc1238713..3fe136bc8345c14adcf5eef68098a9701b1dac52 100644
--- a/bbcli/services/authorization_service.py
+++ b/bbcli/services/authorization_service.py
@@ -292,8 +292,9 @@ def write_to_env_data(session):
     xsrf_value = xsrf[1]
 
     f = open('.env', 'w')
-    f.write("BB_ROUTER=" + BB_ROUTER + "\n")
-    f.write("XSRF=" + xsrf_value + "\n")
+    f.write(f'BB_ROUTER={BB_ROUTER}\n')
+    f.write(f'XSRF={xsrf_value}\n')
+    f.write(f'BB_USERNAME={login_username}\n')
     f.close()
 
 
diff --git a/bbcli/services/content_service.py b/bbcli/services/content_service.py
new file mode 100644
index 0000000000000000000000000000000000000000..182b1049c503dc120c461b1703254cdb1010f2a9
--- /dev/null
+++ b/bbcli/services/content_service.py
@@ -0,0 +1,37 @@
+import json
+from subprocess import call
+from typing import Dict, Any
+import requests
+from bbcli.services.course_service import list_courses
+import click
+
+
+# User gets a tree structure view of the courses content
+# where each content is listed something like this: _030303_1 Lectures Folder
+def list_course_content(cookies: Dict, course_id: str):
+    print('Getting course content!')
+
+
+# If it is a folder, list it like a tree structure view like mentioned above.
+# If it is a document, download and open the document maybe?
+# Find all types of content and have an appropriate response for them. This
+# should maybe be handled in the view...
+def get_content(cookies: Dict, course_id: str, content_id: str):
+    print('Getting content by its ID.')
+
+
+# List all contents of type assignment, should be executed if a flag for example like --content-type assignment or smth is used
+def list_assignments(cookies: Dict, course_id: str):
+    print('Getting all assignments')
+
+# TODO: add methods for all content types like the one above
+
+
+# Create content. This should have a flag which says what kind of content type it is
+
+
+# Create assignment. Creates an assignment
+
+# Delete spesific content
+
+# Update spesific content
\ No newline at end of file
diff --git a/bbcli/services/course_service.py b/bbcli/services/course_service.py
index 6b893e8b0e4e4b688237bc9a8bf9c2586ddc37f7..c69fae73a0ee618a06c3b7bfbb58748c5ee200b0 100644
--- a/bbcli/services/course_service.py
+++ b/bbcli/services/course_service.py
@@ -1,35 +1,29 @@
 import json
-from typing import Dict, Any
+from typing import Dict, Any, List
 import requests
 from datetime import date
 
-def take_start_date(elem):
-    return date.fromisoformat(elem['availability']['duration']['start'].split('T')[0])
+from bbcli.utils.URL_builder import URLBuilder
 
+url_builder = URLBuilder()
 
-def list_courses(cookies: Dict, user_name: str) -> Any:
-    session = requests.Session()
 
-    terms = session.get('https://ntnu.blackboard.com/learn/api/public/v1/terms', cookies=cookies)
-    terms = json.loads(terms.text)['results']
-    
-    # Sort terms by start date to get the two most recent semesters to determine which courses to show
-    for term in terms:
-        if term['availability']['duration']['type'] != 'DateRange':
-            terms.remove(term)
-    terms.sort(key=take_start_date)
+def list_courses(session: requests.Session, user_name: str) -> Any:
+
+    terms = get_terms(session)    
+    sort_terms(terms)
 
     term_1 = terms[len(terms) - 1]
     term_2 = terms[len(terms) - 2]
 
-    course_memberships = session.get('https://ntnu.blackboard.com/learn/api/public/v1/users/userName:{}/courses'.format(user_name), cookies=cookies)
-    course_memberships = json.loads(course_memberships.text)['results']
+    course_memberships = get_course_memberships(session, user_name)
 
     course_list = []
 
     # Get courses from the correct terms
     for course in course_memberships:
-        response = session.get('https://ntnu.blackboard.com/learn/api/public/v3/courses/{}'.format(course['courseId']), cookies=cookies, params={'fields': 'id, name, termId'})
+        url = url_builder.base_v3().add_courses().add_id(course['courseId']).create()
+        response = session.get(url, params={'fields': 'id, name, termId'})
         response = json.loads(response.text)
         if response['termId'] == term_1['id'] or response['termId'] == term_2['id']:
             course_list.append({
@@ -41,10 +35,53 @@ def list_courses(cookies: Dict, user_name: str) -> Any:
 
     return course_list
 
-def list_course(cookies: Dict, course_id:str) -> Any:
-    response = requests.get('https://ntnu.blackboard.com/learn/api/public/v3/courses/{}'.format(course_id), cookies=cookies)
+def list_all_courses(session: requests.Session, user_name: str) -> Any:
+    course_memberships = get_course_memberships(session, user_name)
+
+    course_list = []
+
+    for course in course_memberships:
+        url = url_builder.base_v3().add_courses().add_id(course['courseId']).create()
+        response = session.get(url, params={'fields': 'id, name'})
+        response = json.loads(response.text)
+        course_list.append(response)
+    
+    return course_list
+
+def list_course(session: requests.Session, course_id:str) -> Any:
+    url = url_builder.base_v3().add_courses().add_id(course_id).create()
+    response = session.get(url)
     return json.loads(response.text)
 
-def list_favorite_courses(cookies: Dict, user_name: str) -> Any:
+def list_favorite_courses(session: requests.Session, user_name: str) -> Any:
     return "Blackboard rest api do not have an option for this yet"
     # response = requests.get('https://ntnu.blackboard.com/learn/api/public/v1/users/userName:{}/courses'.format(user_name), cookies=cookies)
+
+
+"""
+
+HELPER FUNCTIONS
+
+"""
+
+def take_start_date(elem):
+    return date.fromisoformat(elem['availability']['duration']['start'].split('T')[0])
+
+def get_terms(session: requests.Session):
+    url = url_builder.base_v1().add_terms().create()
+    terms = session.get(url)
+    terms = json.loads(terms.text)['results']
+    return terms
+
+def sort_terms(terms):
+    # Sort terms by start date to get the two most recent semesters to determine which courses to show
+    for term in terms:
+        if term['availability']['duration']['type'] != 'DateRange':
+            terms.remove(term)
+    terms.sort(key=take_start_date)
+
+def get_course_memberships(session: requests.Session, user_name: str):
+    url = url_builder.base_v1().add_users().add_id(id=user_name, id_type='userName').add_courses().create()
+    course_memberships = session.get(url)
+    course_memberships = json.loads(course_memberships.text)['results']
+    return course_memberships
\ No newline at end of file
diff --git a/bbcli/utils/URL_builder.py b/bbcli/utils/URL_builder.py
new file mode 100644
index 0000000000000000000000000000000000000000..126e55cde999460ab73e36097d918b248143cbcb
--- /dev/null
+++ b/bbcli/utils/URL_builder.py
@@ -0,0 +1,129 @@
+from __future__ import annotations
+from typing import Any
+from abc import ABC, abstractmethod
+
+DOMAIN = 'https://ntnu.blackboard.com'
+API_BASE = '/learn/api/public'
+
+
+class Builder(ABC):
+
+    @property
+    @abstractmethod
+    def product(self) -> None:
+        pass
+
+
+    """
+    Returns the base URL which includes the domain and first part of all the endpoints: domain/learn/api/public/vX,
+    where X is the version from 1 to 3.
+    """
+
+    @abstractmethod
+    def base_v1(self) -> Builder:
+        pass
+
+    @abstractmethod
+    def base_v2(self) -> Builder:
+        pass
+
+    @abstractmethod
+    def base_v3(self) -> Builder:
+        pass
+
+    @abstractmethod
+    def add_courses(self) -> Builder:
+        pass
+
+    @abstractmethod
+    def add_users(self) -> Builder:
+        pass
+
+    @abstractmethod
+    def add_announcements(self) -> Builder:
+        pass
+
+    @abstractmethod
+    def add_contents(self) -> Builder:
+        pass
+
+    @abstractmethod
+    def add_terms(slef) -> Builder:
+        pass
+
+    @abstractmethod
+    def add_id(self, id: str, id_type: str = None) -> Builder:
+        pass
+
+
+class URLBuilder(Builder):
+
+    def __init__(self) -> None:
+        self.reset()
+
+    def reset(self) -> None:
+        self._product = URL()
+
+    @property
+    def product(self) -> URL:
+
+        product = self._product
+        self.reset()
+        return product
+
+
+
+    def base_v1(self) -> URLBuilder:
+        self._product.add(f'{DOMAIN}{API_BASE}/v1')
+        return self
+    
+    def base_v2(self) -> URLBuilder:
+        self._product.add(f'{DOMAIN}{API_BASE}/v2')
+        return self
+
+    def base_v3(self) -> URLBuilder:
+        self._product.add(f'{DOMAIN}{API_BASE}/v3')
+        return self
+
+    def add_courses(self) -> URLBuilder:
+        self._product.add('/courses')
+        return self
+
+    def add_users(self) -> URLBuilder:
+        self._product.add('/users')
+        return self
+    
+    def add_announcements(self) -> URLBuilder:
+        self._product.add('/announcements')
+        return self
+
+    def add_contents(self) -> URLBuilder:
+        self._product.add('/contents')
+        return self
+
+    def add_terms(self) -> URLBuilder:
+        self._product.add('/terms')
+        return self
+
+    def add_id(self, id:str, id_type:str=None) -> URLBuilder:
+        if id_type:
+            self._product.add(f'/{id_type}:{id}')
+        else:
+            self._product.add(f'/{id}')
+        return self
+
+    def create(self) -> str:
+        url = self._product.get_url()
+        self._product = URL()
+        return url
+
+class URL():
+
+    def __init__(self) -> None:
+        self.URL = ''
+
+    def add(self, url_part: str) -> None:
+        self.URL += url_part
+
+    def get_url(self) -> None:
+        return self.URL
\ No newline at end of file
diff --git a/bbcli/utils/error_handler.py b/bbcli/utils/error_handler.py
new file mode 100644
index 0000000000000000000000000000000000000000..3ef18c457e14b69fb63848806eca035cc32ac56f
--- /dev/null
+++ b/bbcli/utils/error_handler.py
@@ -0,0 +1,13 @@
+import requests
+import click
+
+# ERROR HANDLER SHOULD BE USED IN VIEW??
+
+def HTTP_exception_handler(func):
+    def inner_function(*args, **kwargs):
+        try:
+            func(*args, **kwargs)
+        except requests.exceptions.HTTPError as err:
+            click.echo(err)
+            click.Abort()
+    return inner_function     
\ No newline at end of file
diff --git a/bbcli/utils/utils.py b/bbcli/utils/utils.py
index 1f58f831eab864aa0066d68e7abf42634376b209..be69a2a95bd56a92257613d0897eb5eb10c117e7 100644
--- a/bbcli/utils/utils.py
+++ b/bbcli/utils/utils.py
@@ -1,4 +1,8 @@
 from datetime import datetime 
+from typing import Dict, List
+from requests import Session
+import html2text
+
 
 def check_valid_key(obj, key) -> bool:
 	# print("the keys are", obj.keys())
@@ -31,3 +35,16 @@ def check_valid_date(cookies) -> bool:
         return False
 
 
+def set_cookies(session: Session, cookies: List):
+	for cookie in cookies:
+    	 session.cookies.set(cookie['name'], cookie['value'])
+
+
+def set_headers(session: Session, headers: List):
+	for header in headers:
+		session.headers.update(header)
+
+
+def html_to_text(html_data: str):
+	to_text = html2text.HTML2Text()
+	return to_text.handle(html_data)
\ No newline at end of file
diff --git a/bbcli/views/__init__.py b/bbcli/views/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/bbcli/views/announcement_view.py b/bbcli/views/announcement_view.py
new file mode 100644
index 0000000000000000000000000000000000000000..866af312e79460ec6ed2910b0513da259d0f3f16
--- /dev/null
+++ b/bbcli/views/announcement_view.py
@@ -0,0 +1,25 @@
+import click
+from typing import List
+from bbcli.utils.utils import html_to_text
+
+
+def print_announcements(announcements: List):
+    for course in announcements:
+        print_course_announcements(course['course_announcements'], course['course_name'])
+
+def print_course_announcements(course_announcements: List, course_name: str = None):
+    
+    for announcement in course_announcements:
+        if 'body' in announcement:
+            announcement_id = announcement['id']
+            title = announcement['title']
+            body = html_to_text(announcement['body'])
+            created = announcement['created'].split('T')[0]
+
+            click.echo('----------------------------------------------------------------------\n')
+            if course_name:
+                click.echo(f'{course_name}\n')
+            click.echo('{:<15} {:<15}'.format('Id: ', announcement_id))
+            click.echo('{:<15} {:<15}'.format('Title: ', title))
+            click.echo('{:<15} {:<15}'.format('Date: ', created))
+            click.echo('\n{:<15}\n'.format(body))
diff --git a/bbcli/views/content_view.py b/bbcli/views/content_view.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/bbcli/views/course_view.py b/bbcli/views/course_view.py
new file mode 100644
index 0000000000000000000000000000000000000000..2320342b5c914adba28da36c3b9f6f99d7270c9d
--- /dev/null
+++ b/bbcli/views/course_view.py
@@ -0,0 +1,19 @@
+import click
+
+def print_courses(courses):
+    click.echo('\n{:<12} {:<5}\n'.format('Id', 'Course Name'))
+    for course in courses:
+        course_id = course['id']
+        name = course['name']
+        click.echo('{:<12} {:<5}'.format(course_id, name))
+    click.echo('\n\n')
+
+def print_course(course):
+
+    primary_id = course['id']
+    course_id = course['courseId']
+    name = course['name']
+
+    click.echo('\n{:<12} {:<12}'.format('Id:', primary_id))
+    click.echo('{:<12} {:<12}'.format('Course Id:', course_id))
+    click.echo('{:<12} {:<12}\n'.format('Name:', name))
\ No newline at end of file