Browse Source

Merge branch 'master' of github.com:nisstyre56/TextbookEngine

master
wes 9 years ago
parent
commit
209447edad
  1. 7
      src/archive.py
  2. 10
      src/mcmaster/classes.py
  3. 7
      src/scripts/book.tag
  4. 1
      src/scripts/class.tag
  5. 5
      src/scripts/results.tag
  6. 3
      src/scripts/row.tag
  7. 76
      src/scripts/search.tag
  8. 6
      src/search.py
  9. 14
      src/styles/bootstrap.min.css
  10. 64
      src/styles/search.scss
  11. 56
      src/templates/search.html
  12. 18
      src/visualize.py
  13. 1
      src/website.py

7
src/archive.py

@ -5,14 +5,14 @@ from json import loads, dumps
import requests as req import requests as req
searchUrl = "https://archive.org/advancedsearch.php?q={0}&fl%5B%5D=avg_rating&fl%5B%5D=description&fl%5B%5D=identifier&fl%5B%5D=type&sort%5B%5D=&sort%5B%5D=&sort%5B%5D=&rows=50&page=1&output=json&callback=callback&save=yes#raw" searchUrl = "https://archive.org/advancedsearch.php?q={0}&fl%5B%5D=avg_rating&fl%5B%5D=description&fl%5B%5D=identifier&fl%5B%5D=mediatype&fl%5B%5D=type&fl%5B%5D=type&sort%5B%5D=&sort%5B%5D=&sort%5B%5D=&rows=50&page=1&output=json&callback=callback&save=yes#raw"
def searchIA(title, author): def searchIA(title, author):
""" """
Do a search on The Internet Archive for a book Do a search on The Internet Archive for a book
""" """
print("running a search") print("running a search")
requrl = searchUrl.format(quote(title + " " + author)) requrl = searchUrl.format(quote(title) + " AND " + quote(author))
try: try:
results = loads(req.get(requrl).text[9:][0:-1]) results = loads(req.get(requrl).text[9:][0:-1])
except ValueError: except ValueError:
@ -24,7 +24,8 @@ def searchIA(title, author):
return [] return []
docs = results["response"]["docs"] docs = results["response"]["docs"]
urls = [] urls = []
for result in results["response"]["docs"][0:3]: for result in [r for r in results["response"]["docs"][0:10] if r["mediatype"] == "texts"]:
print(result)
urls.append("https://archive.org/details/%s" % result["identifier"]) urls.append("https://archive.org/details/%s" % result["identifier"])
return urls return urls

10
src/mcmaster/classes.py

@ -207,7 +207,7 @@ def parseColumns(subject, html):
classInfo = (list(getSectionInfo(table)) for table in classInfo = (list(getSectionInfo(table)) for table in
islice((table for table in parsed.xpath(".//table") islice((table for table in parsed.xpath(".//table")
if table.xpath("@id") and if table.xpath("@id") and
search(r"ICField[0-9]+\$scroll", table.xpath("@id")[0])), 1, sys.maxint)) search(r"ICField[0-9]+\$scroll", table.xpath("@id")[0])), 1, sys.maxsize))
classNames = ((subject, span.text_content().strip()) for span in parsed.xpath(".//span") classNames = ((subject, span.text_content().strip()) for span in parsed.xpath(".//span")
if span.xpath("@id") and if span.xpath("@id") and
@ -238,7 +238,7 @@ class MosReq(object):
self.codes_ = [] self.codes_ = []
def getlist(self, subject): def getlist(self, subject):
sys.stderr.write("Getting " + subject + "\n") sys.stderr.write("Getting %s\n" % subject.decode("UTF-8"))
first_req = requests.get(searchurl, cookies=self.cookies).content first_req = requests.get(searchurl, cookies=self.cookies).content
# for some reason Mosaic wants us to request it twice, ?????????????????? # for some reason Mosaic wants us to request it twice, ??????????????????
self.statenum = getStateNum(first_req) self.statenum = getStateNum(first_req)
@ -252,7 +252,7 @@ class MosReq(object):
self.statenum = getStateNum(first_req) self.statenum = getStateNum(first_req)
except IndexError: except IndexError:
pass pass
if "Your search will return over" in first_req: if b"Your search will return over" in first_req:
return requests.post(searchurl, return requests.post(searchurl,
data=payload2.format(self.statenum, self.semester), data=payload2.format(self.statenum, self.semester),
@ -295,7 +295,8 @@ def request(codes, lists, semester):
code = codes.get() code = codes.get()
try: try:
lists.put(requester.classes(code)) lists.put(requester.classes(code))
except: except exception:
print(exception)
codes.task_done() codes.task_done()
return return
codes.task_done() codes.task_done()
@ -335,6 +336,7 @@ class CourseInfo(object):
for cl in chain.from_iterable(sections): for cl in chain.from_iterable(sections):
new_sections = [] new_sections = []
for sec in cl[1]: for sec in cl[1]:
print(sec)
if len(sec.day) > 1: if len(sec.day) > 1:
for day in sec.day: for day in sec.day:
new_sections.append(copy.deepcopy(sec)) new_sections.append(copy.deepcopy(sec))

7
src/scripts/book.tag

@ -2,21 +2,21 @@
<div class="text-clip toast"> <div class="text-clip toast">
<p> <p>
<button onclick={getresources} class="btn btn-link"> <button onclick={getresources} class="btn btn-link">
{ booktitle } { booktitle } {bookauthor !== "Ccw" ? "by " + bookauthor : ""}
</button> </button>
<dd> <dd>
<div if={ loading } class="loading"> <div if={ loading } class="loading">
</div> </div>
<p if={ iarchive }> <p if={ iarchive }>
<a target="_blank" href="{ iarchive }"> <a target="_blank" href="{ iarchive }">
<button class="centered btn btn-link"> <button class="centered btn">
Internet Archive Result Internet Archive Result
</button> </button>
</a> </a>
</p> </p>
<p if={ openlib }> <p if={ openlib }>
<a target="_blank" href="{ openlib }"> <a target="_blank" href="{ openlib }">
<button class="centered btn btn-link"> <button class="centered btn">
Open Library Result Open Library Result
</button> </button>
</a> </a>
@ -27,6 +27,7 @@
</dd> </dd>
</p> </p>
</div> </div>
<script> <script>
this.iarchive = false; this.iarchive = false;
this.openlib = false; this.openlib = false;

1
src/scripts/class.tag

@ -34,4 +34,5 @@ showbooks() {
this.update(); this.update();
</script> </script>
</class> </class>

5
src/scripts/results.tag

@ -1,6 +1,9 @@
<results> <results>
<div if={notLoading} class="courses container"> <div if={notLoading} class="courses container">
<row class="course-row columns" each={ rows } data="{ this }" classrow={ row }></row> <row if={rows.length > 0} class="course-row columns" each={ rows } data="{ this }" classrow={ row }></row>
<div if={rows.length <= 0} class="empty">
No Results, Sorry!
</div>
</div> </div>
<script> <script>
clicker() { clicker() {

3
src/scripts/row.tag

@ -4,6 +4,9 @@
data="{ this }"> data="{ this }">
</class> </class>
<script>
this.classrow = opts.classrow this.classrow = opts.classrow
</script>
</row> </row>

76
src/scripts/search.tag

@ -1,51 +1,62 @@
<search> <search>
<form class="form-horizontal search-form" onsubmit={ submit.bind(this) } type="submit"method="get"> <form class="form-horizontal search-form" onsubmit={ submit } type="submit"method="get">
<div class="form-group"> <div class="form-group">
<div class="container"> <div class="container">
<div class="columns">
<div if={ false }
class="help-toast toast toast-primary">
<button onclick={ clearhelp }
class="btn btn-clear float-right">
</button>
Type keywords of your course's name or the course code (e.g. PSYCH 2B03)
</div>
</div>
<div class="columns"> <div class="columns">
<div class="col-sm-8 form-item"> <div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">
<input onfocus={ showHelp } <input onfocus={ showhelp }
class="form-input" class="form-input search"
placeholder="Description" placeholder="Course Description"
type="text" type="text"
name="title"/> name="title">
</div> </input>
<div class="col-sm-2 form-item">
<select class="form-select" aria-labelledby="dLabel" name="sem">
<option value="Fall">Fall</option>
<option value="Winter" selected>Winter</option>
<option value="Spring/Summer">Spring/Summer</option>
</select>
</div>
<div class="col-sm-2 form-item">
<button class="btn btn-primary" type="submit">Search</button>
</div> </div>
</div> </div>
<div class="columns">
<div class="col-sm-6 col-md-6 col-lg-6">
<select class="semester form-select float-right" aria-labelledby="dLabel" name="sem">
<option value="Fall" selected>Fall</option>
<option value="Winter">Winter</option>
<option value="Spring/Summer">Spring/Summer</option>
</select>
</div>
<div class="col-sm-6 col-md-6 col-lg-6">
<button
class="search-btn btn btn-primary float-left tooltip tooltip-bottom"
data-tooltip="Search by keywords"
type="submit">
Search
</button>
</div>
</div>
</div> </div>
</div> </div>
</form> </form>
<div if={ opts.showHelp }
class="help-toast toast toast-primary">
<button onclick={ clearHelp }
class="btn btn-clear float-right">
</button>
Type keywords of your course's name or the course code (e.g. PSYCH 2B03)
</div>
<div if={ opts.booksLoading } class="search-load"> <div if={ opts.booksLoading } class="search-load">
</div> </div>
</search>
<script>
this.showedHelp = false; this.showedHelp = false;
this.waiting = false; this.waiting = false;
function showHelp() { showhelp() {
if (!this.showedHelp) { if (!this.showedHelp) {
this.opts.showHelp = true; this.opts.showHelp = true;
this.update(); this.update();
if (!waiting) { if (!this.waiting) {
waiting = true; this.waiting = true;
window.setTimeout( window.setTimeout(
(function() { (function() {
this.waiting = false; this.waiting = false;
@ -55,7 +66,7 @@ function showHelp() {
} }
} }
function clearHelp() { clearhelp() {
this.showedHelp = true; this.showedHelp = true;
this.opts.showHelp = false; this.opts.showHelp = false;
this.update(); this.update();
@ -66,7 +77,7 @@ function clearHelpTemp() {
this.update(); this.update();
} }
function submit(ev) { submit(ev) {
ev.preventDefault(); ev.preventDefault();
this.showedHelp = true; this.showedHelp = true;
this.opts.showHelp = false; this.opts.showHelp = false;
@ -84,3 +95,6 @@ function submit(ev) {
this.update(); this.update();
}).bind(this)); }).bind(this));
} }
</script>
</search>

6
src/search.py

@ -20,8 +20,8 @@ es = elasticsearch.Elasticsearch()
def summarize(text): def summarize(text):
splitted = text.split(" ") splitted = text.split(" ")
if len(splitted) > 4: if len(splitted) > 6:
return " ".join(splitted[0:4]) + ".." return " ".join(splitted[0:6]) + ".."
return text return text
def sectionToJSON(section): def sectionToJSON(section):
@ -204,7 +204,7 @@ def searchTerms(terms):
if obj.books: if obj.books:
secs["books"] = [ secs["books"] = [
{ {
"booktitle" : summarize(book[0]), "booktitle" : book[0],
"bookauthor" : book[1], "bookauthor" : book[1],
"bookprice" : book[2] "bookprice" : book[2]
} }

14
src/styles/bootstrap.min.css

File diff suppressed because one or more lines are too long

64
src/styles/search.scss

@ -4,6 +4,10 @@ header {
color: $blue; color: $blue;
} }
.form-group {
margin: auto;
}
.wraptext { .wraptext {
white-space: pre-wrap !important; white-space: pre-wrap !important;
} }
@ -77,17 +81,52 @@ a {
margin-right: 0px !important; margin-right: 0px !important;
} }
.form-item { .search {
padding-left: 5px; max-width: 60%;
padding-right: 5px; margin-bottom: 10px;
margin-right: -15px; margin-left: auto;
margin-right: auto;
@media (max-width: 735px) {
max-width: 80%;
}
@media (max-width: 480px) {
max-width: 100%;
margin-bottom: 10px;
}
}
.semester {
margin-bottom: 10px;
margin-right: 5px;
@media (max-width: 480px) {
max-width: 100%;
margin-bottom: 10px;
}
}
.search-btn {
margin-bottom: 10px;
margin-left: 5px;
@media (max-width: 480px) {
max-width: 100%;
margin-bottom: 10px;
}
}
.search-controls {
margin-top: 5px;
margin-left: 20%;
} }
.title { .title {
font-weight: bolder; font-weight: bolder;
@media (min-width: 480px) { float: right;
margin-left: 80px; margin-right: 10%;
} }
.header-text {
margin: auto;
max-width: 80%;
} }
.ui-autocomplete { .ui-autocomplete {
@ -135,13 +174,18 @@ a {
} }
.logo { .logo {
margin-top: 20px; float: left;
margin-left: -175px; margin-left: -20%;
margin-top: 15px;
@media (max-width: 480px) {
margin-left: 45% !important;
}
} }
.page-top { .page-top {
font-size: 15px; font-size: 15px;
width: 50% !important; margin: auto;
width: 80% !important;
} }
.help-toast { .help-toast {

56
src/templates/search.html

@ -1,50 +1,44 @@
{% extends "bootstrap/base.html" %} <meta name="viewport" content="width=device-width, initial-scale=1">
{% block head %}
{{super()}}
<meta name="viewport" content="width=device-width, initial-scale=1">
<header class="text-center nav navbar"> <header class="text-center nav navbar">
<section class="centered page-top navbar-section"> <section class="page-top navbar-section">
<div class="container"> <div class="container header-text">
<div class="columns"> <div class="columns">
<div class="title column col-md-9"><h1>TextBook Commons</h1></div> <div class="col-sm-9 col-md-9 col-lg-9 text-center">
<div class="logo column col-md-3"> <h1 class="title">TextBook Commons</h1>
<figure class="avatar avatar-xl"> </div>
<div class="col-sm-3 col-md-3 col-lg-3">
<figure class="logo avatar avatar-xl">
<img src="https://mgoal.ca/goal.png" />
</figure> </figure>
</div> </div>
</div> </div>
<div class="columns">
<div class="title col-sm-12 col-md-12 col-lg-12">
<h5>Search for your course and start saving money on your books</h5>
</div>
</div>
</div> </div>
<h5>Search for your course and start saving money on your books</h5>
<search></search> <search></search>
</section> </section>
</header> </header>
{% endblock %}
<html> <html>
<figure class="avatar avatar-xl"> <body>
<img src="https://mgoal.ca/goal_small.png" />
</figure>
<body>
{% block content %}
<results></results> <results></results>
{% endblock %}
<footer class="footer"> <footer class="footer">
</footer> </footer>
{% block styles %}
{{super()}}
<link rel="stylesheet" href="/styles/spectre.min.css"> <link rel="stylesheet" href="/styles/spectre.min.css">
<link rel="stylesheet" href="/styles/search.min.css"> <link rel="stylesheet" href="/styles/search.min.css">
{% endblock %}
{% block scripts %} <script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/riot/2.6.7/riot+compiler.min.js"></script>
{{super()}} <script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.22.1/ramda.min.js"></script>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/riot/2.6.7/riot+compiler.min.js"></script> <script type="text/javascript" src="/scripts/tags.min.js"></script>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.22.1/ramda.min.js"></script> <script type="text/javascript" src="/scripts/search.min.js"></script>
<script type="text/javascript" src="/scripts/tags.min.js"></script> <script src="https://code.jquery.com/jquery-2.2.4.min.js"
<script type="text/javascript" src="/scripts/search.min.js"></script> integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44="
{% endblock %} crossorigin="anonymous">
</body> </script>
</body>
</html> </html>

18
src/visualize.py

@ -9,24 +9,8 @@ from operator import attrgetter
import pygal import pygal
import csv import csv
class Textbook(object):
def __init__(self, dept, code, title, author, price):
self.dept = dept
self.code = code
self.title = title
self.author = author
self.price = float(price)
def __repr__(self):
return "Dept = %s, Code = %s, %s by %s, costs $%s" % (self.dept,
self.code,
self.title,
self.author,
self.price)
def courses(): def courses():
with open("./books.csv", "r") as books: with open("./mcmaster/courses.csv", "r") as books:
booksreader = csv.reader(books) booksreader = csv.reader(books)
for row in booksreader: for row in booksreader:
yield row yield row

1
src/website.py

@ -142,7 +142,6 @@ def ClassSearch(configfile=None):
app = Flask(__name__) app = Flask(__name__)
app.register_blueprint(blueprint, url_prefix="/search") app.register_blueprint(blueprint, url_prefix="/search")
Bootstrap(app)
#app.config["scripts"] = "./scripts" #app.config["scripts"] = "./scripts"
#app.config["styles"] = "./styles" #app.config["styles"] = "./styles"
return app return app

Loading…
Cancel
Save