def get_course(code): """Returns all information for course identified by course code. Search is case sensitive """ with pool.get_connection() as sc: # Make sure there is a course with the given code triples = sc.query(Triple(code, "rdf:type", "Course")) if not triples: msg = 'There is no course with code "{0}".'.format(code) raise Exception(msg) course = fetch_rdf_graph(code, dont_follow=["department"]) course["code"] = code # Fetch department and faculty codes separately, as the structure # constructed by fetch_rdf_graph becomes sanely does not # contain the codes. These just go and assume that every course # has both faculty and department. With Noppa scraping this # is necessarily true. triples = sc.query(Triple(course["code"], "department", None)) course["department"] = str(triples[0].object) triples = sc.query(Triple(course["department"], "faculty", None)) course["faculty"] = str(triples[0].object) return course
def search(query): """Return users based on their real names and usernames. Arguments: query -- The search term. Every user whose name or user name contains the query string will be returned. """ with pool.get_connection() as sc: query = query.lower() if isinstance(query, unicode): query = query.encode('utf8') user_ids = set() username_triples = sc.query( Triple(None, '{0}#username'.format(PEOPLE_BASE_URI), None)) unstructured_triples = sc.query( Triple(None, '{0}#unstructured'.format(PEOPLE_BASE_URI), None)) for triple in chain(username_triples, unstructured_triples): name = str(triple.object) if query in name.lower(): if triple.predicate.endswith('unstructured'): name_triples = sc.query(Triple(None, '{0}#name'.format(PEOPLE_BASE_URI), triple.subject)) user_uri = name_triples[0].subject else: user_uri = triple.subject namespace, uid = user_uri.split('#') user_ids.add(uid) return list(user_ids)
def search(query): """Search for courses whose course code or name contains the query string. Search is case insensitive Arguments: query -- The query string. Please use unicode query string, if you want to have a case insensitive search for unicode characters also. """ query = query.lower() if isinstance(query, unicode): query = query.encode("utf8") with pool.get_connection() as sc: # This unfortunately must be done in Python. WQL could possibly help # here. Of course SIB (or Python-KP) is slow as molasses anyway. # Get a list of valid course codes as also Faculties and Departments # have 'name' predicate. course_triples = sc.query(Triple(None, "rdf:type", "Course")) valid_courses = set(str(triple.subject) for triple in course_triples) name_triples = sc.query(Triple(None, "name", None)) course_codes = [] for triple in name_triples: course_code = str(triple.subject) course_name = str(triple.object) if course_code not in valid_courses: continue if query in course_code.lower() or query in course_name.lower(): course_codes.append(course_code) return sorted(course_codes)
def fetch_rdf_graph(subject, dont_follow=None): """Fetch all triples related to a subject and transform them to a graph. First this function fetches all triples with the given subject. Then it calls itself recursively for all such triples that have an URI as their object. The end result is a clean graph of all these triples similar to the output of make_graph(). Arguments: subject -- The subject of triples to fetch. dont_follow -- A list of predicates which are not followed recursively. This is useful if the RDF graph contains recursive references that cause infinite recursion in this function. """ if dont_follow is None: dont_follow = [] with pool.get_connection() as sc: triples = sc.query(Triple(subject, None, None)) graph = {} if not triples: return graph for triple in triples: # Skip triples that define RDF ontology if triple.predicate.startswith(RDF_SYNTAX_NS_URI): continue subject = wrap_if_not_none(str, triple.subject) predicate = wrap_if_not_none(str, triple.predicate) object_ = wrap_if_not_none(str, triple.object) # Strip namespace uri from predicate if isinstance(triple.predicate, uri): predicate = predicate.split('#')[-1] # The last condition is there to prevent wandering into RDF # ontology definitions if isinstance(triple.object, uri) and \ str(triple.predicate) not in dont_follow and \ not object_.startswith(RDF_SCHEMA_URI): value = fetch_rdf_graph(object_, dont_follow) else: value = object_ if subject not in graph: graph[subject] = {} if predicate not in graph[subject]: graph[subject][predicate] = value elif isinstance(graph[subject][predicate], list): graph[subject][predicate].append(value) else: graph[subject][predicate] = [graph[subject][predicate], value] return graph[subject]
def get_all(): """Return a list of user_ids of all users. """ uids = [] with pool.get_connection() as sc: triples = sc.query(Triple(None, 'rdf:type', uri('{0}#Person'.format(PEOPLE_BASE_URI)))) for triple in triples: uid = triple.subject.split('#')[-1] uids.append(uid) return uids
def get_faculties(): """Returns faculties listed in Noppa system ordered by their id.""" with pool.get_connection() as sc: # Get list of faculties with their ids triples = sc.query(Triple(None, "rdf:type", "Faculty")) faculties_ids = [str(triple.subject) for triple in triples] # Get id-name triplets by ids faculties = [] for faculty_id in faculties_ids: faculty = get_faculty_info(faculty_id) faculties.append(faculty) # Sort the list of faculties by their code return sorted(faculties, key=lambda faculty: faculty["code"])
def get_courses_by_department(code): """Returns courses by given department as identified by department code. Department code is case sensitive """ with pool.get_connection() as sc: triples = sc.query(Triple(None, "department", uri(code))) course_codes = [str(triple.subject) for triple in triples] courses = [] for course_code in course_codes: course = get_course(course_code) courses.append(course) # Sort the list of courses by their code return sorted(courses, key=lambda course: course["code"])
def get_friends(user_id): """Get a list of user's friends. Arguments: user_id -- The user id of the user. """ friend_ids = [] with pool.get_connection() as sc: friend_triples = sc.query(Triple( '{0}/ID#{1}'.format(PEOPLE_BASE_URI, user_id), '{0}#Friend'.format(PEOPLE_BASE_URI), None)) for triple in friend_triples: friend_id = triple.object.split('#')[-1] friend_ids.append(friend_id) return friend_ids
def get_pending_friend_requests(self): """Returns a list of people who have requested to connect to this user. A friend request is accepted by making the same request in the opposite direction. """ pending_friend_ids = [] with pool.get_connection() as sc: friend_triples = sc.query(Triple( '{0}/ID#{1}'.format(PEOPLE_BASE_URI, self.user_id), '{0}#PendingFriend'.format(PEOPLE_BASE_URI), None)) for triple in friend_triples: friend_id = triple.object.split('#')[-1] pending_friend_ids.append(friend_id) return pending_friend_ids
def get_faculty_info(code): """Returns faculty info by the given faculty code. Arguments: code -- Faculty code as seen in Noppa's URL when viewing courses by faculty. This is case sensitive. """ with pool.get_connection() as sc: # Make sure there is a faculty with the given code triples = sc.query(Triple(code, "rdf:type", "Faculty")) if not triples: msg = 'There is no faculty with code "{0}".'.format(code) raise Exception(msg) name_triple = sc.query(Triple(code, "name", None)) faculty = {"code": code, "name": str(name_triple[0].object)} return faculty
def get_department_info(code): """Returns department info by the given department code. Arguments: code -- Case sensitive department code """ with pool.get_connection() as sc: # Make sure there is a department with the given code triples = sc.query(Triple(code, "rdf:type", "Department")) if not triples: msg = 'There is no department with code "{0}".'.format(code) raise Exception(msg) name_triple = sc.query(Triple(code, "name", None)) department = {"code": code, "name": str(name_triple[0].object)} return department
def get_departments_by_faculty(faculty_code): """Returns departments by a faculty. Arguments: faculty_code -- The code of the faculty whose departments are returned. Faculty code is case sensitive. """ with pool.get_connection() as sc: triples = sc.query(Triple(None, "faculty", uri(faculty_code))) department_ids = [str(triple.subject) for triple in triples] departments = [] for department_id in department_ids: department = get_department_info(department_id) departments.append(department) # Sort the list of departments by their code return sorted(departments, key=lambda department: department["code"])
def get_completed_courses(user_id): """Returns the completed courses for the given user sorted by most recent completion first. """ user_uri = '{0}/ID#{1}'.format(PEOPLE_BASE_URI, user_id) with pool.get_connection() as sc: all_completed_course_uris = set(triple.subject for triple in sc.query( Triple(None, 'rdf:type', 'CompletedCourse'))) all_user_uris = set(triple.subject for triple in sc.query(Triple(None, 'user', uri(user_uri)))) completed_course_uris = all_completed_course_uris & all_user_uris completed_courses = [] for subject in completed_course_uris: completed_course = fetch_rdf_graph( subject, dont_follow=['user']) del completed_course['user'] completed_courses.append(completed_course) return sorted(completed_courses, key=lambda item: item['date'], reverse=True)
def is_completed_course(self, course_code): subject = '{0}people/{1}/courses/completed/{2}'.format( CLOUDSIZZLE_RDF_BASE, self.user_id, course_code) triple = Triple(subject, 'rdf:type', 'CompletedCourse') with pool.get_connection() as sc: return len(sc.query(triple)) > 0