From b2ffb7d1e9c8ae63093f97fdba1b48bc347fd6c1 Mon Sep 17 00:00:00 2001 From: Nathan Ahrens Date: Thu, 25 Jan 2018 14:44:18 -0500 Subject: [PATCH] Django project so far... Milestone 1 --- bblearn/BlackboardLearn.py | 138 ++++++++++++++++++++ bblearn/_DS_Store | Bin 0 -> 6148 bytes bblearn/bblearn/__init__.py | 0 bblearn/bblearn/settings.py | 121 +++++++++++++++++ bblearn/bblearn/urls.py | 22 ++++ bblearn/bblearn/wsgi.py | 16 +++ bblearn/db.sqlite3 | 0 bblearn/learn/_DS_Store | Bin 0 -> 6148 bytes bblearn/learn/__init__.py | 0 bblearn/learn/admin.py | 3 + bblearn/learn/apps.py | 5 + bblearn/learn/migrations/__init__.py | 0 bblearn/learn/models.py | 3 + bblearn/learn/static/_DS_Store | Bin 0 -> 6148 bytes bblearn/learn/static/learn/courses.css | 143 +++++++++++++++++++++ bblearn/learn/static/learn/loginPage.css | 108 ++++++++++++++++ bblearn/learn/static/learn/main.css | 131 +++++++++++++++++++ bblearn/learn/templates/_DS_Store | Bin 0 -> 6148 bytes bblearn/learn/templates/learn/_DS_Store | Bin 0 -> 6148 bytes bblearn/learn/templates/learn/courses.html | 71 ++++++++++ bblearn/learn/templates/learn/error.html | 50 +++++++ bblearn/learn/templates/learn/index.html | 58 +++++++++ bblearn/learn/tests.py | 3 + bblearn/learn/urls.py | 9 ++ bblearn/learn/views.py | 83 ++++++++++++ bblearn/manage.py | 15 +++ 26 files changed, 979 insertions(+) create mode 100644 bblearn/BlackboardLearn.py create mode 100644 bblearn/_DS_Store create mode 100644 bblearn/bblearn/__init__.py create mode 100644 bblearn/bblearn/settings.py create mode 100644 bblearn/bblearn/urls.py create mode 100644 bblearn/bblearn/wsgi.py create mode 100644 bblearn/db.sqlite3 create mode 100644 bblearn/learn/_DS_Store create mode 100644 bblearn/learn/__init__.py create mode 100644 bblearn/learn/admin.py create mode 100644 bblearn/learn/apps.py create mode 100644 bblearn/learn/migrations/__init__.py create mode 100644 bblearn/learn/models.py create mode 100644 bblearn/learn/static/_DS_Store create mode 100644 bblearn/learn/static/learn/courses.css create mode 100644 bblearn/learn/static/learn/loginPage.css create mode 100644 bblearn/learn/static/learn/main.css create mode 100644 bblearn/learn/templates/_DS_Store create mode 100644 bblearn/learn/templates/learn/_DS_Store create mode 100644 bblearn/learn/templates/learn/courses.html create mode 100644 bblearn/learn/templates/learn/error.html create mode 100644 bblearn/learn/templates/learn/index.html create mode 100644 bblearn/learn/tests.py create mode 100644 bblearn/learn/urls.py create mode 100644 bblearn/learn/views.py create mode 100644 bblearn/manage.py diff --git a/bblearn/BlackboardLearn.py b/bblearn/BlackboardLearn.py new file mode 100644 index 0000000..b4714e7 --- /dev/null +++ b/bblearn/BlackboardLearn.py @@ -0,0 +1,138 @@ +import requests +# For AuthToken +import datetime +import time + +import json + +requests.packages.urllib3.disable_warnings() + +# class responsible for managing authentication with the bb server +class AuthToken(): + target_url = '' + + def __init__(self, URL, key, secret): + + self.KEY = key + self.SECRET = secret + self.PAYLOAD = { + 'grant_type':'client_credentials' + } + + self.TOKEN = None + self.target_url = URL + self.EXPIRES_AT = '' + + def getKey(self): + return self.KEY + + def getSecret(self): + return self.SECRET + + def setNewToken(self): + oauth_path = '/learn/api/public/v1/oauth2/token' + OAUTH_URL = self.target_url + oauth_path + + session = requests.session() + + # Authenticate + r = session.post(OAUTH_URL, data=self.PAYLOAD, auth=(self.KEY, self.SECRET), verify=False) + + if r.status_code == 200: + parsed_json = json.loads(r.text) + self.TOKEN = parsed_json['access_token'] + self.EXPIRES = parsed_json['expires_in'] + m, s = divmod(self.EXPIRES, 60) + + self.NOW = datetime.datetime.now() + self.EXPIRES_AT = self.NOW + datetime.timedelta(seconds = s, minutes = m) + + return r.status_code + + def setToken(self): + if self.setNewToken() == 200: + if self.isExpired(self.EXPIRES_AT): + self.setToken() + + else: + # Auth error!!! + self.EXPIRES = 0 + m, s = divmod(self.EXPIRES, 60) + + self.NOW = datetime.datetime.now() + self.EXPIRES_AT = self.NOW + datetime.timedelta(seconds = s, minutes = m) + + def getToken(self): + #if token time is less than a one second then + # print that we are pausing to clear + # re-auth and return the new token + if self.isExpired(self.EXPIRES_AT): + self.setToken() + return self.TOKEN + + def getTokenExpires(self): + return self.EXPIRES_AT + + def revokeToken(self): + revoke_path = '/learn/api/public/v1/oauth2/revoke' + revoke_URL = self.target_url + revoke_path + + self.PAYLOAD = { + 'token':self.TOKEN + } + + if self.TOKEN != '': + for keys,values in self.PAYLOAD.items(): + print("\t\t\t" + keys + ":" + values) + session = requests.session() + + # revoke token + r = session.post(revoke_URL, data=self.PAYLOAD, auth=(self.KEY, self.SECRET), verify=False) + + if r.status_code == 200: + # successful revoke + pass + else: + # could not revoke + pass + else: + # Token is not currently set + pass + + + def isExpired(self, expiration_datetime): + expired = False + + time_left = (expiration_datetime - datetime.datetime.now()).total_seconds() + if time_left < 1: + expired = True + + return expired + +# class responsible for providing an interface with the bb server, using AuthTocken class +class LearnInterface: + def __init__(self, url, key, secret): + + self.server_url = url + self.auth_instance = AuthToken(url, key, secret) + self.auth_instance.setToken() + self.session = requests.session() + + #return the response from the post call + def post(self, url, json_data): + return self.session.post(self.server_url + url,data=json_data,auth=(self.auth_instance.getKey(),self.auth_instance.getSecret()),verify=False) + + #return the response of the get call + def get(self, url): + return self.session.get(self.server_url + url, headers={'Authorization':'Bearer ' + self.auth_instance.getToken()}, verify=False) + + #return the response of the delete call + def delete(self, url): + return self.session.delete(self.server_url + url, auth=(self.auth_instance.getKey(),self.auth_instance.getSecret()), verify=False) + + #return the response of the patch call + def patch(self, url, json_data): + return self.session.patch(self.server_url + url,data=json_data,auth=(self.auth_instance.getKey(),self.auth_instance.getSecret()),verify=False) + + def getTokenExpires(self): + return self.auth_instance.getTokenExpires() diff --git a/bblearn/_DS_Store b/bblearn/_DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..f0a75b8ec30b09e5ec3a024517d3f0dbb6de0248 GIT binary patch literal 6148 zcmeHK%}T>S5Z>*NCWzRBsK>o{>!GEEdJ#gc2X8_|4=Qa!f(^u^B&kJfByXW_W3S0rjWK3`B9=^Oz7QNoU6GRZAaXfJU)!5b z+pVLzXyo{;{bsKJ(x6z2X7`AJ*a_}HqxZDgcgZnP2WP_$Vc#X zoY`Fs2wsdagzO}<-*k3nH}jF*WdMLRMotBw2ml5uVQvG51w!+rbCOY>JR%coc+j=S z(ZKdYdoEf#Gy|G}Wn+NO?ixf8gM~VKe&6hY??rLB{LV7jTz+lcC=`ssmT}wah2vIi z#iOWU4X?$Q=eV}AFT&9OvMu}4bI0xC&Pf==mKV6gsqmXCFL1(fBOC=zB-S~%;vVLT zjoQWC$)r|2D)CxU;*)y4T;kQkYLXbn-a+N~tkZvZoIEAZFOpM+SCEixg`e<>#!QL# ztzqDY!5#W3r+|gK(1!u|f&>?$sY`4LNvPLE_b8 zjLns)NEf0R&Dp6b=IEWSiF^6s;Xj3miIb5NsFqMciC`_gz%2cLW z3?|dj&sChMFqJ6NfvM($shyeXP?*>q*XJS}m?=?@ngPwgECX5jS)}*>^ymJ6Hc5YJ z1~daJ#Q@7STg?WRq~6xK;^?jAs2x-iic2Mm6dcrZEDU;z_fdu5947S5Z>*Nrihq>sK>o{>!GEE>Olyx9=r(^J*e1(1RID+X;Op6O5Q@>$Vc#X zoY~!$mMVA>u`@9H&Cbs3vR}f^E@O<_W3S1W$rv+05lb~_z7QNoU6PXaAaXfJIP0ZOI!n$B~!FdCr`40J(CZTXQGR z+pWX8Xiw@Q?{pe<(K={NCWf)Q-#j|)-#fjeLoN-GbwZs51 zu*g7Jbxo}QC*QyS7n7(*3=jkViUD5f_PRD~N!Qk;&0(z-pnXsjj4Kq*QoxX<7-F#$ c?}17Izd!@f(pV@24+vcZBn{LM1Ha0^CnwfWv;Y7A literal 0 HcmV?d00001 diff --git a/bblearn/learn/static/learn/courses.css b/bblearn/learn/static/learn/courses.css new file mode 100644 index 0000000..7ddfa13 --- /dev/null +++ b/bblearn/learn/static/learn/courses.css @@ -0,0 +1,143 @@ + +/*Styles the outer border that contains this pages contents*/ +#homePageContainer{ + + display: block; + top:35; + margin-left: auto; + margin-right: auto; + width: 710px; + border: solid; + border-color: #4C3059; + overflow:auto; + height: 10%; +} + +/*Places the purple background for the Homepage background*/ +#homePageLabelBackground{ + + display: block; + margin-left: auto; + margin-right: auto; + width: 100%; + height: 35px; + top:0px; + left: 0px; + background-color: #66137c; +} + +/*Contains the label for the homepage and styles it with an opaque black color*/ +#homePageLabelContainer{ + + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.5); + +} + +/*It is the label of the homepage*/ +#homePageLabel{ + + position: relative; + top: 7px; + left: 15px; + text-align: center; + font-size: 16px; + font-weight: bold; + color: white; +} + +/*Contains the dropdown bar for the user to choose what they want to do*/ +#courseActionsContainer{ + + border-top: solid; + border-bottom: solid; + padding-top: 5px; + width: 100%; + height: 50px; +} + +select{ + + + text-align: center; + margin-left: 5px; + margin-top: 2px; + border: solid; + border-width: thin; + border-color: grey; + font-size: 30px; +} + +.selectdiv{ + + position: relative; + float: left; + width: 210px; + margin: 0; +} + +#submit{ + + position: relative; + float: right; + margin-top: 2px; + margin-right: 285px; + display: inline-block; + left: 25px; + width: 30%; + height: 40px; + background-color: white; + border: solid; + border-width: thin; + border-color: grey; + border-radius: 5px; + font-size: 35px; + line-height: 15px; + + + +} + + +/*contains the course, might not on this page*/ +#coursesContainer{ + + width: 100%; +} + +.container{ + + display: block; + border-top: solid; + border-width: 2px; + padding-bottom: 1px; + width: 100%; + font-size: 25px; +} + +input[type=checkbox] { + + position: inline; + height: 25px; + width: 25px; + background-color: #eee; + border-radius: 10%; + margin-top: 5px; + vertical-align: middle; +} + +.checkMark{ + + -webkit-border-radius: 5px; + display: inline; + + vertical-align: middle; + margin-left: 2px; + width: auto; + height: 25px; + background-color: white; + border-style: solid; + border-width: thin; + border-color: grey; +} diff --git a/bblearn/learn/static/learn/loginPage.css b/bblearn/learn/static/learn/loginPage.css new file mode 100644 index 0000000..8067593 --- /dev/null +++ b/bblearn/learn/static/learn/loginPage.css @@ -0,0 +1,108 @@ + +/* +End for everything in the Header +*/ + +/* +Start for everything After the Header +*/ +#loginInformation{ + + height: 223px; +} + +#login{ + + height: 100%; +} +#loginLabelBackground{ + + display: block; + margin-left: auto; + margin-right: auto; + width: 210px; + height: 35px; + top:0px; + left: 0px; + background-color: #66137c; + +} + +#loginLabelContainer{ + + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.5); +} + +#loginLabel{ + + display: block; + text-align: center; + font-size: 30px; + font-style: italic; + color: white; + +} + + +#loginContainer{ + + + display: block; + top:35; + margin-left: auto; + margin-right: auto; + width: 210px; + height: 255px; + border: solid; + border-color: #4C3059; + border-top: none; + +} + +input[type=text], input[type=password], select { + + position: relative; + left: 10px; + width: 90%; + padding: 8px 8px; + margin: 8px 0; + display: inline-block; + border: 1px solid #ccc; + border-radius: 4px; + box-sizing: border-box; + font-size: 13px; + line-height: 10px; + border-bottom: solid; + +} + +#userName{ + + margin-bottom: 15px; +} + +.formLabel{ + + position: relative; + left: 10px; + font-size: 20px; + +} + +#submit{ + + -webkit-border-radius: 5px; + position: relative; + display: inline-block; + bottom: 3px; + left: 25px; + width: 75%; + height: 25px; + background-color: white; + border-style: solid; + border-width: thin; + border-color: grey; + +} diff --git a/bblearn/learn/static/learn/main.css b/bblearn/learn/static/learn/main.css new file mode 100644 index 0000000..fc75cf1 --- /dev/null +++ b/bblearn/learn/static/learn/main.css @@ -0,0 +1,131 @@ + +#body{ + margin: 0; + background-color: #F9F1FD; +} + +/* +Start for everything in the Header +*/ +#heading{ + + background-color: #66137c; + width: 100%; + height: 150px; + overflow: visible; + +} + +/* +Styles the black background for the title and subTitle +*/ +#titleContainer{ + + position: absolute; + width: 350px; + height: 75px; + top:0px; + left: 0px; + background-color: rgba(0, 0, 0, 0.5); + border-bottom-right-radius: 25px; +} + +/* +Styles the Main Title +*/ +#title{ + + position: absolute; + width: 550px; + height: 35px; + top:15px; + left: 15px; + color: #E2C536; + font-size: 33px; + font-weight: bold; +} + +/* +Styles the Ashland University that Appears under the Main Title +*/ +#subTitle{ + + position: absolute; + width: 160px; + height: 24px; + top:50px; + left: 40%; + color: white; + font-size: 18px; + font-weight: bold; +} + +/* +Styles the black background for Sign out +*/ +#signOutBackground{ + + position: absolute; + width: auto; + height: 50px; + top:0px; + right: 10px; + background-color: rgba(0, 0, 0, 0.5); + border-radius: 10px; + border-top-left-radius: 0; + border-top-right-radius: 0; +} + +/* +Styles the sign out text +*/ +#signOutContainer{ + + float:left; + height: 24px; + text-align: center; + margin-left: 10px; + margin-right: 10px; + line-height: 24px; + vertical-align: center; + white-space: nowrap; + color: white; +} + +#signOut{ + + float: right; + margin-right: 5px; + text-decoration: underline; + color: white; +} +/* +End for everything in the Header +*/ + +/* +Start for everything After the Header +*/ +#midSection{ + + top: 150px; + width: 100%; +} + +#footer{ + + position: fixed; + bottom: 0px; + background-color: rgba(90, 29, 118, 0.67); + width: 100%; + height: 20px; +} + +#footerText{ + + display: block; + margin-left: auto; + margin-right: auto; + color: white; + width: 223px; +} diff --git a/bblearn/learn/templates/_DS_Store b/bblearn/learn/templates/_DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..f12e8cec7cca6afeec690ed95db7e5ce8d6250a4 GIT binary patch literal 6148 zcmeHK%}T>S5T32orij>ssK>o{>!GDW@gRg+58i}`9#k}GiVdXM(xeuxmE3&*eIwsM z-$tDMsiaiBRa9nR_M6Pk%x1ro-3|b-#=x%vlmNg&m6$8y@QKKIsWXx@o&q9MH6m{q z_qixMH0<9WitgHyOkY zw|}ah0>AAU`$&lJ!*;#npgp`Ot?h{@af7Jc&xD_y1d%U>4KaxPSk*anlMd#pg)U0# zqtSM4r_8sBZbx_H`$x?y!yllMRf7|FLL;+5KW>E{ zzM>4zxWlWe(-Pg@Bx`!ME1FGzkhB0^9^Q^rOeVK0{BLG^o$o4NJN+mW(G}L5Y#{Rr zWD*0!05LEp2F!_LEzhYwl_ds;8W_iJpi7V&Gpf!17I}*}yHCyLD!B@~-8mm#9)?T&nRS1r2o-W30T2H&KY8xMgRZ+ literal 0 HcmV?d00001 diff --git a/bblearn/learn/templates/learn/_DS_Store b/bblearn/learn/templates/learn/_DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..6200d64eed85f8b8031a12c5353b8bd1ed1e2dd2 GIT binary patch literal 6148 zcmeHKO-sW-5PhpX6utE5aeskD@CSsF-o%S|x3K{WZ7ppI9`n>(7wZgwiTmm zjqmz@ujSEe8LV}T#70fQKrj#t1OuaGfOodY^x81`U?3O>2EG}P^C7bd7LKi<9v$rT z2|%3CtU_Jh5|Wc03&+-w9!j!QqNOH(VkAqaJ$qc?*cw_olCI2oeC4mlOVZV8&l-+Y z7)Boq1Ot5rE^RoI`+vz#X7G{UPl-`55Dfe?2GXQ_Di_?8->pBkCwFaTdtnoixK + + + + Courses + + + {% load static %} + + + + + + + + + + +
+
+
+ Self Service Tool 1000 +
+
+ Ashland University +
+
+
+
+ Hello, {{name}} +
+ Sign out +
+
+
+ + +
+
+
+
+ Select one or more courses to add or remove a Teaching Assistant or Guest from a course or courses +
+
+
+
+ +
+ +
+
+ + {{classes | safe}} + +
+
+
+ + + + + diff --git a/bblearn/learn/templates/learn/error.html b/bblearn/learn/templates/learn/error.html new file mode 100644 index 0000000..d5cad0f --- /dev/null +++ b/bblearn/learn/templates/learn/error.html @@ -0,0 +1,50 @@ + + + + + Error + + + {% load static %} + + + + + + + + + + +
+
+
+ Self Service Tool 1000 +
+
+ Ashland University +
+
+
+
+ Hello, {{name}} +
+ Sign out +
+
+
+ + +
+ +

An error has been encountered!

+

{{ error }}

+ +
+ + + + + diff --git a/bblearn/learn/templates/learn/index.html b/bblearn/learn/templates/learn/index.html new file mode 100644 index 0000000..8bf7e30 --- /dev/null +++ b/bblearn/learn/templates/learn/index.html @@ -0,0 +1,58 @@ + + + + + Login + + + + {% load static %} + + + + + + + + + + +
+
+
+ Self Service Tool 1000 +
+
+ Ashland University +
+
+
+ + +
+
+
+
+ Login +
+
+
+
{% csrf_token %} + + +
+ + +
+ +
+
+
+
+ + + + + diff --git a/bblearn/learn/tests.py b/bblearn/learn/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/bblearn/learn/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/bblearn/learn/urls.py b/bblearn/learn/urls.py new file mode 100644 index 0000000..4fc6f01 --- /dev/null +++ b/bblearn/learn/urls.py @@ -0,0 +1,9 @@ +from django.urls import path +from django.conf.urls.static import static +from . import views + +urlpatterns = [ + path('', views.index, name='index'), + path('courses',views.courses, name='courses'), + +] diff --git a/bblearn/learn/views.py b/bblearn/learn/views.py new file mode 100644 index 0000000..66c7388 --- /dev/null +++ b/bblearn/learn/views.py @@ -0,0 +1,83 @@ +from django.shortcuts import render +from django.template import loader, engines, Template +from BlackboardLearn import LearnInterface +import json + +# Erich +#secret = 'DM3ioqNu07Wlo2OxXHYgJNgeqbo8dxT9' +#key = '31496793-121b-4ab5-a068-83a9c20faed4' + +# Desktop +#key = "0de73b0f-68e7-48cc-b1e9-0fbefe209b74" +#secret = "2Fz6vO82Y035LfoYxlQrY7xyV21SAYPK" + +# Laptop +key = "45ff63ad-e072-42fb-b6af-3c33bff846b4" +secret = "cQXOMrwe0pxMaTQbnozmUvjCxzeGSbKM" + +server = 'https://localhost:9877' + +interface = LearnInterface(server, key, secret) + +#Create your views here. + +def index(request): + template = loader.get_template('learn/index.html') + context ={ + + } + return render(request, 'learn/index.html', context) + +def courses(request): + user_name ='' + class_list ='' + r = None + + + if request.method == "POST": + user_name = request.POST.get('username') + path = '/learn/api/public/v1/users/userName:' + user_name + '/courses' + r = interface.get(path) + if r.status_code == 404: + return render(request, 'learn/error.html', { 'error' : 'Error 404: The username you entered is not valid!' }) + elif r.status_code == 403: + return render(request, 'learn/error.html', { 'error' : 'Error 403: You are not authorized!' }) + elif r.status_code == 400: + return render(request, 'learn/error.html', { 'error' : 'Error 400: There was an error communicating with Blackboard!' }) + else: + # How did we get this far? Should have had a post request with the username. + return render(request, 'learn/error.html', { 'error' : 'No POST request!' }) + + if r.text: + res = json.loads(r.text) + + results = res['results'] + + for resu in results: + if resu['courseRoleId'] == 'Instructor': + path = '/learn/api/public/v1/courses/' + resu['courseId'] + r1 = interface.get(path) + if r1.text: + res1 = json.loads(r1.text) + #html += "" + courseId + "
" + class_list += '' + + # Get the user's name + path = '/learn/api/public/v1/users/userName:' + user_name + r = interface.get(path) + + name = '' + + if r.text: + res = json.loads(r.text) + + name_data = res['name'] + name += name_data['given'] + " " + name_data['family'] + + print("Token expires: " + str(interface.getTokenExpires())) + + context ={ + 'name': name, + 'classes': class_list, + } + return render(request, 'learn/courses.html', context) diff --git a/bblearn/manage.py b/bblearn/manage.py new file mode 100644 index 0000000..66a52d8 --- /dev/null +++ b/bblearn/manage.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python +import os +import sys + +if __name__ == "__main__": + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "bblearn.settings") + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv)