From f6a72b0a19a4cca73ea4d5c48ad39d23fe2817a8 Mon Sep 17 00:00:00 2001 From: magnus2142 <magnus.bredeli@hotmail.com> Date: Fri, 1 Apr 2022 18:06:49 +0200 Subject: [PATCH] Added more create content methods --- bbcli/cli.py | 7 ++- bbcli/commands/contents.py | 79 ++++++++++++++++++++++--- bbcli/services/announcements_service.py | 2 +- bbcli/services/contents_service.py | 59 +++++++++++++++--- bbcli/services/courses_service.py | 9 ++- bbcli/services/utils/content_builder.py | 4 +- bbcli/utils/utils.py | 2 +- 7 files changed, 137 insertions(+), 25 deletions(-) diff --git a/bbcli/cli.py b/bbcli/cli.py index 279f9b8..efa09ae 100644 --- a/bbcli/cli.py +++ b/bbcli/cli.py @@ -13,7 +13,7 @@ import click from bbcli.commands.courses import list_courses from bbcli.commands.announcements import list_announcements, create_announcement, delete_announcement, update_announcement -from bbcli.commands.contents import list_contents, create_content, create_document, create_file +from bbcli.commands.contents import create_courselink, create_folder, list_contents, create_content, create_document, create_file, create_web_link from bbcli.services.authorization_service import login load_dotenv() @@ -110,4 +110,7 @@ def create(ctx): # create.add_command(create_content) create.add_command(create_document) -create.add_command(create_file) \ No newline at end of file +create.add_command(create_file) +create.add_command(create_web_link) +create.add_command(create_folder) +create.add_command(create_courselink) \ No newline at end of file diff --git a/bbcli/commands/contents.py b/bbcli/commands/contents.py index b740156..bcbd748 100644 --- a/bbcli/commands/contents.py +++ b/bbcli/commands/contents.py @@ -1,21 +1,25 @@ from datetime import datetime import click -from bbcli.entities.content_builder_entitites import FileOptions, StandardOptions +from bbcli.entities.content_builder_entitites import FileOptions, StandardOptions, WeblinkOptions from bbcli.services import contents_service from bbcli.views import content_view import os def standard_options(function): - function = click.option('-h', '--hide-content', is_flag=True)(function) - function = click.option('-r', '--reviewable', is_flag=True)(function) - function = click.option('--start-date', type=str)(function) - function = click.option('--end-date', type=str)(function) + function = click.option('-h', '--hide-content', is_flag=True, help='Hide contents for students')(function) + function = click.option('-r', '--reviewable', is_flag=True, help='Make content reviewable')(function) + function = click.option('--start-date', type=str, help='When to make content available. Format: DD/MM/YY HH:MM:SS')(function) + function = click.option('--end-date', type=str, help='When to make content unavailable. Format: DD/MM/YY HH:MM:SS')(function) return function def file_options(function): function = click.option('-n', '--new-window', 'launch_in_new_window', is_flag=True)(function) return function +def web_link_options(function): + function = click.option('-n', '--new-window', 'launch_in_new_window', is_flag=True)(function) + return function + #, help='List a spesific course with the corresponding id' @click.command(name='list') @@ -24,7 +28,6 @@ def file_options(function): # @click.option('-a', '--all/--no-all', 'show_all', default=False, help='Lists all courses you have ever been signed up for') @click.pass_context def list_contents(ctx, course_id: str=None, content_id: str=None): - """ This command lists contents of a course. """ @@ -57,7 +60,7 @@ def upload_file(ctx): @click.pass_context def create_document(ctx, course_id: str, parent_id: str, title: str, hide_content: bool, reviewable: bool, start_date: str=None, end_date: str=None): """ - Creates a document content in blackboard + Creates a document content """ standard_options = StandardOptions(hide_content=hide_content, reviewable=reviewable) @@ -79,7 +82,7 @@ def create_file(ctx, course_id: str, parent_id: str, title: str, file_path: str, launch_in_new_window:bool, hide_content: bool, reviewable: bool, start_date: str=None, end_date: str=None): """ - Creates a file content in blackboard + Creates a file content """ file_options = FileOptions(launch_in_new_window) @@ -104,3 +107,63 @@ def validate_dates(standard_options: StandardOptions, start_date: str, end_date: click.echo('Value format is not valid, please see --help for more info') raise click.Abort() + + +@click.command(name='web-link') +@click.argument('course_id', required=True, type=str) +@click.argument('parent_id', required=True, type=str) +@click.argument('title', required=True, type=str) +@click.argument('url', required=True, type=str) +@standard_options +@web_link_options +@click.pass_context +def create_web_link(ctx, course_id: str, parent_id: str, title: str, url: str, + launch_in_new_window:bool, hide_content: bool, reviewable: bool, + start_date: str=None, end_date: str=None): + """ + Create a web link content + """ + web_link_options = WeblinkOptions(launch_in_new_window) + standard_options = StandardOptions(hide_content, reviewable) + validate_dates(standard_options, start_date, end_date) + response = contents_service.create_externallink(ctx.obj['SESSION'], course_id, parent_id, title, url, web_link_options, standard_options) + print(response) + + +@click.command(name='folder') +@click.argument('course_id', required=True, type=str) +@click.argument('title', required=True, type=str) +@click.option('-p', '--parent_id', required=False, type=str, help='Id of parent folder') +@click.option('--is-bb-page', is_flag=True, help='Make folder a blackboard page') +@standard_options +@click.pass_context +def create_folder(ctx, course_id: str, parent_id: str, title: str, + hide_content: bool, reviewable: bool, is_bb_page: bool = False, + start_date: str=None, end_date: str=None): + """ + Create a folder either in top level or inside another content + """ + standard_options = StandardOptions(hide_content, reviewable) + validate_dates(standard_options, start_date, end_date) + response = contents_service.create_folder(ctx.obj['SESSION'], course_id, parent_id, title, is_bb_page, standard_options) + print(response) + +@click.command(name='course-link') +@click.argument('course_id', required=True, type=str) +@click.argument('parent_id', required=True, type=str) +@click.argument('title', required=True, type=str) +@click.argument('target_id', required=True, type=str) +@standard_options +@click.pass_context +def create_courselink(ctx, course_id: str, parent_id: str, title: str, target_id: str, + hide_content: bool, reviewable: bool, + start_date: str=None, end_date: str=None): + """ + Create a course link content which redirects user to the target content + """ + standard_options = StandardOptions(hide_content, reviewable) + validate_dates(standard_options, start_date, end_date) + response = contents_service.create_courselink(ctx.obj['SESSION'], course_id, parent_id, title, target_id, standard_options) + print(response) + + diff --git a/bbcli/services/announcements_service.py b/bbcli/services/announcements_service.py index 985bd53..b8689ba 100644 --- a/bbcli/services/announcements_service.py +++ b/bbcli/services/announcements_service.py @@ -68,7 +68,7 @@ def delete_announcement(session: requests.Session, course_id: str, announcement_ def update_announcement(session: requests.Session, course_id: str, announcement_id: str): announcement = list_announcement(session=session, course_id=course_id, announcement_id=announcement_id) - MARKER = '# Everything below is ignored\n' + MARKER = '# Everything below is ignored.\n' editable_data = { 'title': announcement['title'], 'body': announcement['body'], diff --git a/bbcli/services/contents_service.py b/bbcli/services/contents_service.py index 887b042..7cce7aa 100644 --- a/bbcli/services/contents_service.py +++ b/bbcli/services/contents_service.py @@ -51,7 +51,7 @@ def list_assignments(cookies: Dict, course_id: str): # NB: Alle options sende som values i enkle fields i bodyen # Alle disse blir sendt til post content endpoint. title, body er samme. Options varirerer. Største ulikheten -# er i content-handler. None kan også ha attachments. +# er i content-handler. Noen kan også ha attachments. # Tror svaret er en ContentBuilder @@ -105,23 +105,66 @@ def create_file(session: requests.Session, course_id: str, parent_id: str, title # Title, URL, body, eventuelt attachments?, Weblink options: open in new window?, Standard options: as above -def create_externallink(): - pass +def create_externallink(session: requests.Session, course_id: str, parent_id: str, title: str, url: str, web_link_options: WeblinkOptions, standard_options: StandardOptions): + + data = content_builder\ + .add_parent_id(parent_id)\ + .add_title(title)\ + .add_standard_options(standard_options)\ + .add_weblink_options(web_link_options)\ + .add_content_handler_externallink(url)\ + .create() + + data = json.dumps(data) + url = generate_create_content_url(course_id, parent_id) + response = session.post(url, data=data) + return response.text # Title, body, Standard options: as above +def create_folder(session: requests.Session, course_id: str, parent_id: str, title: str, is_bb_page:bool, standard_options: StandardOptions): + + data_body = input_body() + + data = content_builder\ + .add_title(title)\ + .add_body(data_body)\ + .add_standard_options(standard_options)\ + .add_content_handler_folder(is_bb_page=is_bb_page) + + if parent_id: + url = generate_create_content_url(course_id, parent_id) + data.add_parent_id(parent_id) + else: + url = url_builder.base_v1().add_courses().add_id(course_id).add_contents().create() + data = data.create() + + data = json.dumps(data) + response = session.post(url, data=data) + return response.text -def create_folder(): - pass # Title, body, location(?), targetId content, Standard Options: as above +# FUNKER IKKE PGA targetType +def create_courselink(session: requests.Session, course_id: str, parent_id: str, title: str, target_id: str, standard_options: StandardOptions): -def create_courselink(): - pass + data_body = input_body() -# Se egen metode i BBL REST API + data = content_builder\ + .add_title(title)\ + .add_body(data_body)\ + .add_standard_options(standard_options)\ + .add_content_handler_courselink(target_id=target_id)\ + .create() + + data = json.dumps(data) + url = generate_create_content_url(course_id, parent_id) + response = session.post(url, data=data) + return response.text + +# Se egen metode i BBL REST API def create_assignment(): pass diff --git a/bbcli/services/courses_service.py b/bbcli/services/courses_service.py index c69fae7..a7fbae8 100644 --- a/bbcli/services/courses_service.py +++ b/bbcli/services/courses_service.py @@ -51,11 +51,14 @@ def list_all_courses(session: requests.Session, user_name: str) -> Any: 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) + response.raise_for_status() + + return json.loads(response.text) -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) +# 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) """ diff --git a/bbcli/services/utils/content_builder.py b/bbcli/services/utils/content_builder.py index 53be014..7bc3a11 100644 --- a/bbcli/services/utils/content_builder.py +++ b/bbcli/services/utils/content_builder.py @@ -176,9 +176,9 @@ class ContentBuilder(Builder): def add_content_handler_courselink(self, target_id: str, target_type: str = 'Unset') -> Builder: self._product.add({ 'contentHandler' : { - 'id': 'resource/x-bb-folder', + 'id': 'resource/x-bb-courselink', 'targetId': target_id, - 'targeType': target_type + 'targetType': target_type } }) return self diff --git a/bbcli/utils/utils.py b/bbcli/utils/utils.py index 809888f..4921ba4 100644 --- a/bbcli/utils/utils.py +++ b/bbcli/utils/utils.py @@ -51,7 +51,7 @@ def html_to_text(html_data: str): return to_text.handle(html_data) def input_body(): - MARKER = '# Everything below is ignored\n' + MARKER = '# Everything below is ignored. Leave blank if you want empty body.\n' body = click.edit('\n\n' + MARKER) if body is not None: body = body.split(MARKER, 1)[0].rstrip('\n') -- GitLab