Skip to content
Snippets Groups Projects
Commit b0491d08 authored by williamforbrigd's avatar williamforbrigd
Browse files

get a specific content

parent 1986daad
No related branches found
No related tags found
No related merge requests found
......@@ -5,8 +5,6 @@ import requests
from bbcli.utils.utils import set_cookies, set_headers
# import typer
from bbcli import __app_name__, __version__
from bbcli.endpoints import get_user, get_course_contents, get_contents
# from bbcli.endpoints import get_user, get_course_contents, get_assignments
import os
from dotenv import load_dotenv
from bbcli import check_valid_date, check_response
......@@ -14,7 +12,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
from bbcli.commands.contents import list_contents, get_content
from bbcli.services.authorization_service import login
def initiate_session():
......@@ -83,12 +81,8 @@ def contents(ctx):
"""
pass
entry_point.add_command(get_user)
entry_point.add_command(get_course_contents)
entry_point.add_command(get_contents)
contents.add_command(list_contents)
contents.add_command(create_content)
contents.add_command(get_content)
load_dotenv()
cookies = {'BbRouter' : os.getenv("BB_ROUTER")}
......
import click
from bbcli.services import contents_service
from bbcli.views import content_view
import os
# from bbcli.views.contents_view import list_tree, create_tree, get_content
from bbcli.views import contents_view
import time
import click
from bbcli import check_response
from bbcli.entities.Node import Node
from bbcli.entities.Node2 import Node2
from bbcli.utils.URL_builder import URLBuilder
from bbcli.utils.content_handler import content_handler
#, help='List a spesific course with the corresponding id'
@click.command(name='list')
@click.argument('course_id', required=True, type=str)
@click.argument('content_id', required=False, type=str)
# @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):
url_builder = URLBuilder()
"""
This command lists contents of a course.
"""
response = None
base_url = 'https://ntnu.blackboard.com/learn/api/public/v1/'
if content_id:
print('GEtting spesific content from a course')
@click.command(name='list')
@click.argument('course_id', default='_27251_1')
@click.option('--folder-id')
@click.pass_context
def list_contents(ctx, course_id: str, folder_id=None):
'''
Get the contents\n
Folders are blue and have an id \n
Files are white
'''
start = time.time()
response = contents_service.list_contents(ctx.obj['SESSION'], course_id, folder_id)
print(response)
if folder_id is not None:
data = response.json()
root = Node(data, True)
worklist = [root]
res = get_children(ctx, course_id, worklist, [])
contents_view.create_tree(root, res)
else:
print('Printing content tree from a course, course', course_id)
folders = response.json()['results']
root = None
for folder in folders:
root = Node(folder, True)
worklist = [root]
res = get_children(ctx, course_id, worklist, [])
contents_view.create_tree(root, res)
end = time.time()
print(f'\ndownload time: {end - start} seconds')
@click.command(name='get')
@click.argument('course_id', required=True, type=str)
@click.argument('node_id', required=True, type=str)
@click.pass_context
def get_content(ctx, course_id: str, node_id: str):
response = contents_service.get_content(ctx.obj['SESSION'], course_id, node_id)
data = response.json()
if data['contentHandler']['id'] == content_handler['document']:
contents_view.open_vim()
elif data['contentHandler']['id'] == content_handler['file'] or data['contentHandler']['id'] == content_handler['document'] or data['contentHandler']['id'] == content_handler['assignment']:
click.confirm("This is a .docx file, do you want to download it?", abort=True)
response = contents_service.get_file(ctx.obj['SESSION'], course_id, node_id)
@click.command(name='create')
@click.argument('course_id', required=True, type=str)
......@@ -30,167 +68,25 @@ def list_contents(ctx, course_id: str=None, content_id: str=None):
def create_content(ctx, course_id: str, content_id: str):
contents_service.test_create_assignment(ctx.obj['SESSION'], course_id, content_id)
import time
import requests
import bbcli.cli as cli
import click
from anytree import Node as Nd, RenderTree
from colorama import Fore, Style
from bbcli import check_response
from bbcli.entities.Node import Node
from bbcli.entities.Node2 import Node2
from bbcli.utils.URL_builder import URLBuilder
url_builder = URLBuilder()
base_url = 'https://ntnu.blackboard.com/learn/api/public/v1/'
def get_children(session, worklist, url, acc, count: int = 0):
def get_children(ctx, course_id, worklist, acc, count: int = 0):
count = count + 1
key = 'hasChildren'
if len(worklist) == 0:
return acc
else:
node = worklist.pop()
id = node.data['id']
tmp = url[:url.index('contents') + len('contents')]
old = f'{tmp}/{id}/children'
response = session.get(old, cookies=cli.cookies)
node_id = node.data['id']
response = contents_service.get_children(ctx.obj['SESSION'], course_id, node_id)
if check_response(response) == False:
return acc
else:
children = response.json()['results']
for i in range(len(children)):
# TODO: Add list of children instead of bool
if key in children[i] and children[i][key] == True:
# if children[i]['contentHandler'] == content_types['folder']:
child = Node(children[i], True, node)
worklist.append(child)
acc.append(child)
else:
child = Node(children[i], False, node)
acc.append(child)
return get_children(session, worklist, url, acc)
def get_children2(session, worklist, url, acc, count: int = 0):
count = count + 1
key = 'hasChildren'
if len(worklist) == 0:
return
else:
node = worklist.pop()
id = node.data['id']
tmp = url[:url.index('contents') + len('contents')]
old = f'{tmp}/{id}/children'
response = session.get(old, cookies=cli.cookies)
if check_response(response) == False:
return acc
else:
children = response.json()['results']
parent = Node2(node)
for i in range(len(children)):
# TODO: Add list of children instead of bool
if key in children[i] and children[i][key] == True:
# if children[i]['contentHandler'] == content_types['folder']:
# child = Node(children[i], True, parent)
child = Node2(children[i])
parent.children.append(child)
worklist.append(child)
# acc.append(child)
else:
child = Node2(children[i])
parent.children.append(child)
# child = Node(children[i], False, parent)
# acc.append(child)
return get_children(session, worklist, url, acc)
@click.command(name='get-contents')
@click.argument('course_id', default='_27251_1')
@click.option('--folder-id')
def get_contents(course_id: str, folder_id=None):
'''
Get the contents\n
Folders are blue and have an id \n
Files are white
'''
session = requests.Session()
if folder_id is not None:
url = f'{base_url}courses/{course_id}/contents/{folder_id}'
else:
url = f'{base_url}courses/{course_id}/contents'
start = time.time()
response = session.get(url, cookies=cli.cookies)
if check_response(response) == False:
return
else:
if folder_id is not None:
data = response.json()
root = Node(data, True)
worklist = [root]
res = get_children(session, worklist, url, [])
create_tree(root, res)
else:
folders = response.json()['results']
root = None
for folder in folders:
root = Node(folder, True)
worklist = [root]
get_children(session, worklist, url, [])
print(root.data['title'])
for child in root.children:
print(child.data['title'])
end = time.time()
print(f'\ndownload time: {end - start} seconds')
def list_tree(root, contents):
for content in contents:
parent = Nd(content.parent.data['title'])
this = Nd(content.data['title'], parent)
for pre, fill, node in RenderTree(root_node):
print("%s%s" % (pre, node.name))
def create_tree(root, nodes):
parents = []
root_node = Nd(root.data['title'])
parent = root_node
parents.append(parent)
folders = dict()
folders[root.data['title']] = root.data['id']
for i in range(len(nodes)):
id = nodes[i].data['id']
title = nodes[i].data['title']
if (nodes[i].has_children):
for parent in parents:
if (parent.name == nodes[i].parent.data['title']):
node = Nd(title, parent)
folders[title] = id
parents.append(node)
continue
node = Nd(title, root_node)
folders[title] = id
parents.append(node)
else:
for parent in parents:
if (parent.name == nodes[i].parent.data['title']):
node = Nd(title, parent)
folders[title] = ''
for pre, fill, node in RenderTree(root_node):
folder_id = folders[node.name]
if folder_id == '':
print("%s%s" % (pre, node.name))
else:
print(f'{pre}{Fore.BLUE}{folder_id} {node.name} {Style.RESET_ALL}')
return get_children(ctx, course_id, worklist, acc)
\ No newline at end of file
......@@ -8,20 +8,62 @@ import requests
from bbcli.services.courses_service import list_courses
from bbcli.utils.URL_builder import URLBuilder
from bbcli.utils.utils import check_response
url_builder = URLBuilder()
# 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!')
def list_contents(session: requests.Session, course_id, folder_id):
if folder_id is not None:
url = url_builder.base_v1().add_courses().add_id(course_id).add_contents().add_id(folder_id).create()
else:
url = url_builder.base_v1().add_courses().add_id(course_id).add_contents().create()
response = session.get(url)
if check_response(response) is False:
return
else:
return response
# get the children of a specific folder
def get_children(session: requests.Session, course_id: str, node_id: str):
url = url_builder.base_v1().add_courses().add_id(course_id).add_contents().add_id(node_id).add_children().create()
return session.get(url)
# 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.')
def get_content(session: requests.Session, course_id: str, node_id: str):
url = url_builder.base_v1().add_courses().add_id(course_id).add_contents().add_id(node_id).create()
print(url)
return session.get(url)
def get_file(session: requests.Session, course_id: str, node_id: str):
# https://ntnu.blackboard.com/learn/api/public/v1/courses/_27251_1/contents/_1685326_1
url = url_builder.base_v1().add_courses().add_id(course_id).add_contents().add_id(node_id).add_attachments()
current = url.create()
response = session.get(current)
data = response.json()
if check_response(response) == False:
return
else:
print("kommer her")
id = data['results'][0]['id']
# url = url.add_id(id).add_download().create()
url = url_builder.base_v1().add_courses().add_id(course_id).add_contents().add_id(node_id).add_attachments().add_id(id).add_download().create()
print(url)
response = session.get(url)
print(response.headers)
import urllib.request
with urllib.request.urlopen(url) as f:
html = f.read().decode('utf-8')
print(html)
return response
# List all contents of type assignment, should be executed if a flag for example like --content-type assignment or smth is used
......
......@@ -63,6 +63,10 @@ class Builder(ABC):
def add_id(self, id: str, id_type: str = None) -> Builder:
pass
@abstractmethod
def add_download(self) -> Builder:
pass
class URLBuilder(Builder):
......@@ -121,6 +125,10 @@ class URLBuilder(Builder):
self._product.add('/attachments')
return self
def add_download(self) -> Builder:
self._product.add('/download')
return self
def add_id(self, id:str, id_type:str=None) -> URLBuilder:
if id_type:
self._product.add(f'/{id_type}:{id}')
......@@ -128,6 +136,7 @@ class URLBuilder(Builder):
self._product.add(f'/{id}')
return self
def create(self) -> str:
url = self._product.get_url()
self._product = URL()
......
content_handler = dict()
content_handler['document'] = 'resource/x-bb-document'
content_handler['externallink'] = 'resource/x-bb-externallink'
content_handler['folder'] = 'resource/x-bb-folder'
content_handler['courselinnk'] = 'resource/x-bb-courselink'
content_handler['forumlink'] = 'resource/x-bb-forumlink'
content_handler['blti-link'] = 'resource/x-bb-blti-link'
content_handler['file'] = 'resource/x-bb-file'
content_handler['asmt-test-link'] = 'resource/x-bb-asmt-test-link'
content_handler['assignment'] = 'resource/x-bb-assignment'
\ No newline at end of file
from anytree import Node as Nd, RenderTree
from colorama import Fore, Style
from bbcli.utils.utils import html_to_text
import click
def list_tree(root, contents):
for content in contents:
parent = Nd(content.parent.data['title'])
this = Nd(content.data['title'], parent)
for pre, fill, node in RenderTree(root_node):
print("%s%s" % (pre, node.name))
def create_tree(root, nodes):
parents = []
root_node = Nd(root.data['title'])
parent = root_node
parents.append(parent)
folders = dict()
folders[root.data['title']] = root.data['id']
for i in range(len(nodes)):
id = nodes[i].data['id']
title = nodes[i].data['title']
if (nodes[i].has_children):
for parent in parents:
if (parent.name == nodes[i].parent.data['title']):
node = Nd(title, parent)
folders[title] = id
parents.append(node)
continue
node = Nd(title, root_node)
folders[title] = id
parents.append(node)
else:
for parent in parents:
if (parent.name == nodes[i].parent.data['title']):
node = Nd(title, parent)
folders[title] = ''
for pre, fill, node in RenderTree(root_node):
folder_id = folders[node.name]
if folder_id == '':
click.echo("%s%s" % (pre, node.name))
else:
click.echo(f'{pre}{Fore.BLUE}{folder_id} {node.name} {Style.RESET_ALL}')
import sys, tempfile, os
from subprocess import call
def open_vim(data):
str += data['title'] + '\n'
str += html_to_text(data['body'])
EDITOR = os.environ.get('EDITOR','vim') #that easy!
# initial_message = b"" # if you want to set up the file somehow
# initial_message = bytearray(str)
initial_message = bytearray(str, encoding='utf8')
with tempfile.NamedTemporaryFile(suffix=".tmp") as tf:
tf.write(initial_message)
tf.flush()
call([EDITOR, tf.name])
# do the parsing with `tf` using regular File operations.
# for instance:
tf.seek(0)
edited_message = tf.read()
print (edited_message.decode("utf-8"))
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment