def change_user_group(id_user, id_group, new_id_group, pos_lat=0.0, pos_lon=0.0): groupCollection = mongodb.get_db().get_collection('groups') group = groupCollection.find_one({'_id': ObjectId(id_group)}) for m in group["members"]: if m["id_user"] == id_user: member = m group["members"].remove(m) if "size" in group: group["size"] -= 1 else: group["size"] = len(group["members"]) groupCollection.update({'_id': ObjectId(id_group)}, {"$set": {"members": group["members"], "size": group["size"]}}) group = groupCollection.find_one({'_id': ObjectId(new_id_group)}) group["members"].append(member) if "size" in group: group["size"] += 1 else: group["size"] = len(group["members"]) groupCollection.update({'_id': ObjectId(new_id_group)}, {"$set": {"members": group["members"], "size": group["size"]}}) groupsActivityCollection = mongodb.get_db().get_collection('groups_activity') timestamp = int(round(time.time() * 1000)) activity_entry = {"id_course": group["id_course"], "id_user": id_user, "former_id_group": ObjectId(id_group), "new_id_group": ObjectId(new_id_group), "timestamp": timestamp, "lat": pos_lat, "lon": pos_lon} groupsActivityCollection.insert(activity_entry)
def profile_badge(request, badgeid, id=None): if (badgeid): if(not id): if(not request.user.id): return HttpResponseRedirect("/auth/login") user = request.user id = request.user.id else: user = User.objects.get(username=id) id = user.id badge = get_db().get_collection('badge').find({"id_user": id, "id_badge": int(badgeid)})[0] hashed_email = hashlib.sha256(user.email + settings.BADGES_HASH_SALT).hexdigest() badge['id'] = badge['_id'] return render_to_response('profile/badge.html', { "id":id, 'request': request, "user_view_profile": user, "badges_count": get_db().get_collection('badge').find({"id_user": id}).count(), "hashed_email": hashed_email, "badge": badge, "openbadges_service_url": settings.BADGES_SERVICE_URL, }, context_instance=RequestContext(request)) else: return HttpResponseBadRequest()
def obj_delete(self, request, **kwargs): obj = self.obj_get(request, **kwargs) #submissions and reviews must be deleted too submissions = get_db().get_collection('peer_review_submissions') submissions.remove({'kq': obj.kq_id}) reviews = get_db().get_collection('peer_review_reviews') reviews.remove({'kq': obj.kq_id}) super(PrivatePeerReviewAssignmentResource, self).obj_delete(request, **kwargs)
def update_following_blog_user(self, id, following, extra=None): get_db().get_collection(self.col_user).update({"id_user": id}, {"$set": {"following": following}}) # xAPI if extra: user = User.objects.get(pk=id) course = None resource = { 'type': 'microblogfollow', 'user_id': extra['user_id'] } geolocation = extra.get('geolocation') x_api.learnerInteracts(user, resource, course, geolocation)
def unenroll_student(course, student): from moocng import mongodb from bson.objectid import ObjectId from moocng.x_api import utils as x_api if course.has_groups: groupCollection = mongodb.get_db().get_collection('groups') group = groupCollection.find_one( { 'id_course': course.id, 'members.id_user':student.id } ) if(group): for m in group["members"]: if(m["id_user"] == student.id): group["members"].remove(m) if "size" in group: group["size"] -= 1 else: group["size"] = len(group["members"]) groupCollection.update({'_id': ObjectId(group["_id"])}, {"$set": {"members": group["members"], "size": group["size"]}}) course.students.through.objects.get(student=student, course=course).delete() geolocation = { 'lat': 0.0, 'lon': 0.0 } x_api.learnerUnenrollsInMooc(student, course, geolocation)
def on_activity_created_task(activity_created, unit_activity, course_activity): db = get_db() kq = KnowledgeQuantum.objects.get(id=activity_created["kq_id"]) kq_type = kq.kq_type() # KQ data = {"viewed": 1} if kq_type == "Video": data["passed"] = 1 stats_kq = db.get_collection("stats_kq") stats_kq.update({"kq_id": activity_created["kq_id"]}, {"$inc": data}, safe=True) # UNIT data = {} if unit_activity == 1: # First activity of the unit data["started"] = 1 elif kq.unit.knowledgequantum_set.count() == unit_activity: data["completed"] = 1 # TODO passed if data.keys(): stats_unit = db.get_collection("stats_unit") stats_unit.update({"unit_id": kq.unit.id}, {"$inc": data}, safe=True) # COURSE course_kqs = KnowledgeQuantum.objects.filter(unit__course__id=activity_created["course_id"]).count() data = {} if course_activity == 1: # First activity of the course data["started"] = 1 elif course_kqs == course_activity: data["completed"] = 1 # TODO passed if data.keys(): stats_course = db.get_collection("stats_course") stats_course.update({"course_id": activity_created["course_id"]}, {"$inc": data}, safe=True)
def forwards(self, orm): from moocng.mongodb import get_db db = get_db() activity = db.get_collection("groups") activity.create_index([("id_course", pymongo.ASCENDING)])
def teacheradmin_stats(request, course_slug): course = get_object_or_404(Course, slug=course_slug) is_enrolled = course.students.filter(id=request.user.id).exists() stats_course = get_db().get_collection('stats_course') stats = stats_course.find_one({'course_id': course.id}) if stats is not None: data = { 'enrolled': course.students.count(), 'started': stats.get('started', -1), 'completed': stats.get('completed', -1), } if course.threshold is not None: #if the course doesn't support certification, then don't return the #'passed' stat since it doesn't apply data['passed'] = stats.get('passed', -1) return render_to_response('teacheradmin/stats.html', { 'course': course, 'is_enrolled': is_enrolled, 'initial_data': simplejson.dumps(data), }, context_instance=RequestContext(request)) else: messages.error(request, _(u"There are no statistics for this course.")) return HttpResponseRedirect(reverse('teacheradmin_info', args=[course_slug]))
def update_stats(submitted, data_kq=None, data_unit=None, data_course=None): db = get_db() data_kq = data_kq or {} data_unit = data_unit or {} data_course = data_course or {} # KQ # TODO passed if data_kq.keys(): stats_kq = db.get_collection('stats_kq') stats_kq.update( {'kq_id': submitted['kq_id']}, {'$inc': data_kq}, safe=True ) # UNIT # TODO passed if data_unit.keys(): stats_unit = db.get_collection('stats_unit') stats_unit.update( {'unit_id': submitted['unit_id']}, {'$inc': data_unit}, safe=True ) # COURSE # TODO passed if data_course.keys(): stats_course = db.get_collection('stats_course') stats_course.update( {'course_id': submitted['course_id']}, {'$inc': data_course}, safe=True )
def clone_activity_user_course(user, copy_course, original_course=None, force_email=False): if not original_course: original_course = copy_course.created_from if not original_course: raise ValueError("This course needs a original course") try: course_student_relation = user.coursestudent_set.get(course=copy_course) except CourseStudent.DoesNotExist: return ([], [], []) file_name = get_trace_clone_file_name(original_course, copy_course) file_path = get_trace_clone_file_path(file_name) f = open(file_path) trace_ids = json.loads(f.read()) f.close() if not copy_course.pk == trace_ids['Course'][str(original_course.pk)]: raise ValueError mongo_db = mongodb.get_db() new_act_docs = _clone_activity_user_course(mongo_db, trace_ids, user, copy_course, original_course) insert_answer_docs, update_answer_docs = _clone_answer_user_course( mongo_db, trace_ids, user, copy_course, original_course) if (new_act_docs or insert_answer_docs or update_answer_docs or course_student_relation.old_course_status != 'c' or force_email): if course_student_relation.old_course_status != 'c': course_student_relation.old_course_status = 'c' course_student_relation.save() if not settings.DEBUG: send_cloned_activity_email(original_course, copy_course, user) return (new_act_docs, insert_answer_docs, update_answer_docs)
def dispatch(self, request_type, request, **kwargs): db = get_db() self.user_answers = get_user(request, db.get_collection('answers')) self.user_activity = get_user(request, db.get_collection('activity')) return super(KnowledgeQuantumResource, self).dispatch(request_type, request, **kwargs)
def teacheradmin_stats(request, course_slug): course = get_object_or_404(Course, slug=course_slug) is_enrolled = course.students.filter(id=request.user.id).exists() stats_course = get_db().get_collection('stats_course') stats = stats_course.find_one({'course_id': course.id}) if stats is not None: data = { 'enrolled': course.students.count(), 'started': stats.get('started', -1), 'completed': stats.get('completed', -1), } if course.threshold is not None: #if the course doesn't support certification, then don't return the #'passed' stat since it doesn't apply data['passed'] = stats.get('passed', -1) return render_to_response('teacheradmin/stats.html', { 'course': course, 'is_enrolled': is_enrolled, 'initial_data': simplejson.dumps(data), }, context_instance=RequestContext(request)) else: messages.error(request, _(u"There are no statistics for this course.")) return HttpResponseRedirect( reverse('teacheradmin_info', args=[course_slug]))
def save_review(kq, reviewer, user_reviewed, criteria, comment): parsed_criteria = [[int(a), int(b)] for (a, b) in criteria] db = get_db() submissions = db.get_collection("peer_review_submissions") reviews = db.get_collection("peer_review_reviews") submission = submissions.find_one({ "author": user_reviewed.id, "kq": kq.id }) peer_review_review = { "submission_id": submission.get("_id"), "author": user_reviewed.id, "comment": comment, "created": datetime.utcnow(), "reviewer": reviewer.id, "criteria": parsed_criteria, "kq": kq.id, "unit": kq.unit.id, "course": kq.unit.course.id } review_exists = (reviews.find({ "submission_id": submission.get("_id"), "reviewer": reviewer.id, }).count() > 0) if review_exists: raise IntegrityError("Already exist one review for this submission and" " reviewer") reviews.insert(peer_review_review) submissions.update({ "author": user_reviewed.id, "kq": kq.id, }, { "$inc": { "reviews": 1, }, "$unset": { "assigned_to": 1, "assigned_when": 1, }, "$push": { "reviewers": reviewer.id, } }) submissions.update({ "author": reviewer.id, "kq": kq.id, }, {"$inc": { "author_reviews": 1, }}) return peer_review_review
def handle(self, *args, **options): users = User.objects.all() if options["user"]: users = users.filter(pk=options["user"]) if not users: raise CommandError(u"User %s does not exist" % options["user"]) self.message("Migrating the user: %s" % users[0].username) elif settings.NUM_MIGRATE_MARK_DAILY is not None: email_list = options["email_list"] if not email_list: raise CommandError(u"Please you have to pass the email list") first_day = datetime.strptime(settings.FIRST_DAY_MIGRATE_MARK, '%Y-%m-%d') today = datetime.today() num_days = (today - first_day).days start_pk = num_days * settings.NUM_MIGRATE_MARK_DAILY + 1 end_pk = (num_days + 1) * settings.NUM_MIGRATE_MARK_DAILY self.message("Migrating the users from pk=%s to pk=%s " % (start_pk, end_pk)) users = users.filter(pk__gte=start_pk, pk__lte=end_pk) max_pk = User.objects.aggregate(Max('pk'))['pk__max'] if not users and end_pk >= max_pk: send_mail('The mark migration is finished', 'The mark migration is finished', settings.DEFAULT_FROM_EMAIL, email_list.split(',')) db = get_db() for user in users: for course in user.courses_as_student.all(): for unit in course.unit_set.scorables(): for kq in unit.knowledgequantum_set.all(): updated_kq, passed_kq_now = update_kq_mark(db, kq, user, course.threshold) self.update_passed(db, 'stats_kq', passed_kq_now, {'kq_id': kq.pk}) updated_unit, passed_unit_now = update_unit_mark(db, unit, user, course.threshold) self.update_passed(db, 'stats_unit', passed_unit_now, {'unit_id': unit.pk}) updated_course, passed_course_now = update_course_mark(db, course, user) self.update_passed(db, 'stats_course', passed_course_now, {'course_id': course.pk})
def is_valid(self, bundle, request): if not bundle.data or not ("kq" in bundle.data): return {'__all__': 'Expected kq id'} errors = {} db = get_db() collection = db.get_collection("peer_review_submissions") exists = collection.find({ "kq": bundle.data["kq"], "author": unicode(request.user.id) }) if exists.count() > 0: msg = "Already exists a submission for kq=%s and user=%s" % ( bundle.data["kq"], request.user.id) logger.error(msg) errors["kq"] = [msg] errors["author"] = [msg] text = bundle.data.get("text", "") max_text_leng = getattr(settings, "PEER_REVIEW_TEXT_MAX_SIZE", 5000) if len(text) > max_text_leng: errors["text"] = "Text is longer than %s chars" % max_text_leng return errors
def handle(self, *args, **options): activity = get_db().get_collection('activity') to_fix = activity.find({'$where': 'function() { return this.unit_id == null; }'}) fixed_counter = 0 removed_counter = 0 total = to_fix.count() if total > 0: for act in to_fix: try: kq = KnowledgeQuantum.objects.get(id=int(act['kq_id'])) activity.update( {'kq_id': act['kq_id']}, {'$set': {'unit_id': kq.unit.id}}, ) fixed_counter += 1 except KnowledgeQuantum.DoesNotExist: activity.remove({'kq_id': act['kq_id']}) removed_counter += 1 if ((total / 100) % (fixed_counter + removed_counter)) == 0: percent = int(total / (fixed_counter + removed_counter)) print 'Progress: %d%% of %d' % (percent, total) print 'Fixed %d activities, removed %d' % (fixed_counter, removed_counter)
def search_posts(self, query, page): postCollection = get_db().get_collection(self.col_post) mongoQuery = {'$regex': '.*%s.*' % (query)} posts = postCollection.find({'text': mongoQuery})[page:page+10].sort("date",pymongo.DESCENDING) return self._process_post_list(posts)
def update_mark(submitted): from moocng.courses.marks import calculate_kq_mark, calculate_unit_mark, calculate_course_mark updated_kq_mark = updated_unit_mark = updated_course_mark = False passed_kq = passed_unit = passed_course = False kq = KnowledgeQuantum.objects.get(pk=submitted['kq_id']) unit = kq.unit course = kq.unit.course user = User.objects.get(pk=submitted['user_id']) mark_kq, mark_normalized_kq = calculate_kq_mark(kq, user) db = get_db() # KQ updated_kq_mark, passed_kq = update_kq_mark(db, kq, user, course.threshold, new_mark_kq=mark_kq, new_mark_normalized_kq=mark_normalized_kq) # UNIT if not updated_kq_mark: return (updated_kq_mark, updated_unit_mark, updated_course_mark, passed_kq, passed_unit, passed_course) mark_unit, mark_normalized_unit = calculate_unit_mark(kq.unit, user) updated_unit_mark, passed_unit = update_unit_mark(db, unit, user, course.threshold, new_mark_unit=mark_unit, new_mark_normalized_unit=mark_normalized_unit) # COURSE if not updated_unit_mark: return (updated_kq_mark, updated_unit_mark, updated_course_mark, passed_kq, passed_unit, passed_course) mark_course, units_info = calculate_course_mark(unit.course, user) updated_course_mark, passed_course = update_course_mark(db, course, user, mark_course) return (updated_kq_mark, updated_unit_mark, updated_course_mark, passed_kq, passed_unit, passed_course)
def _process_post_children(self, post, id_user=None): postCollection = get_db().get_collection(self.col_post) from_zone = tz.tzutc() to_zone = tz.tzlocal() post['replies'] = [] for child in post['children']: try: post_child = postCollection.find({ '$and': [ {'_id': child}, {'$or': [ {'deleted': {'$exists': False} }, {'deleted': False} ] } ] }).limit(1)[0] if post_child and len(post_child['children']) > 0: self._process_post_children(post_child, id_user) post_child["date"] = datetime.strptime(post_child.get("date"), "%Y-%m-%dT%H:%M:%S.%f").replace(tzinfo=from_zone).astimezone(to_zone).strftime('%d %b %Y').upper() if("original_date" in post_child): post_child["original_date"] = datetime.strptime(post_child.get("original_date"), "%Y-%m-%dT%H:%M:%S.%f").replace(tzinfo=from_zone).astimezone(to_zone).strftime('%d %b %Y').upper() post_child["id"] = post_child.pop("_id") post_child["text"] = self._process_urls(post_child["text"]) post_child["text"] = self._process_hashtags(post_child["text"]) if id_user: user_voted = [x for x in post_child["voters"] if id_user == x["id_user"]] post_child["user_vote"] = 0 for user_vote in user_voted: post_child["user_vote"] += user_vote["vote"] post['replies'].append(post_child) except: pass
def profile_user(request, id, byid=False): if(not id): case = None if(not request.user.id): return HttpResponseRedirect('/auth/login') id = request.user.id user = request.user else: case = _getCase(request,id) if byid: user = User.objects.get(pk=id) else: user = User.objects.get(username=id) id = user.id courses = get_courses_user_is_enrolled(user) return render_to_response('profile/user.html', { 'id': id, 'case': case, 'badges_count': get_db().get_collection('badge').find({'id_user': id}).count(), 'request': request, 'courses': courses, 'is_user': True, 'user_view_profile': user, }, context_instance=RequestContext(request))
def insert_p2p_if_does_not_exists_or_raise(p2p_submission, submissions=None): if submissions is None: db = get_db() submissions = db.get_collection("peer_review_submissions") if submissions.find({'kq': p2p_submission['kq'], 'author': p2p_submission['author']}).count() > 0: raise BadRequest(_('You have already sent a submission. Please reload the page')) return submissions.insert(p2p_submission)
def save_retweet(self, post_id, user_id, username, extra=None): postCollection = get_db().get_collection(self.col_post) post = postCollection.find_one({"$and": [{"id_user":user_id},{"id_original_post":ObjectId(post_id)}]}) if(not post): postCollection.update({"$or": [{"_id": ObjectId(post_id)}, {"id_original_post": ObjectId(post_id)}]}, {"$inc": {"shared": 1}}, multi=True) post = postCollection.find_one({"_id": ObjectId(post_id)}) post["id_author"] = post["id_user"] post["id_user"] = user_id post["id_original_post"] = post["_id"] post["original_date"] = post["date"] post["date"] = datetime.utcnow().isoformat() post["shared_by"] = "@%s" % (username) del post["_id"] rtpost_id = super(Microblog,self).insert_post(post) # xAPI if extra: user = User.objects.get(pk=user_id) course = None resource = { 'type': 'microblogshare', 'url': 'https://%s%s#%s' % (settings.API_URI, reverse('profile_posts_byid', kwargs={'id': user_id}), rtpost_id), 'name': 'Microblog post', 'description': 'This is a blog post' } geolocation = extra.get('geolocation') x_api.learnerSubmitsAResource(user, resource, course, geolocation) return True else: return False
def teacheradmin_stats_kqs(request, course_slug): course = get_object_or_404(Course, slug=course_slug) if not 'unit' in request.GET: return HttpResponse(status=400) unit = get_object_or_404(Unit, id=request.GET['unit']) if not unit in course.unit_set.all(): return HttpResponse(status=400) data = [] activity = get_db().get_collection('activity') answers = get_db().get_collection('answers') kq_list = unit.knowledgequantum_set.all() for kq in kq_list: kq_data = { 'id': kq.id, 'title': kq.title, 'viewed': 0 } question = None if kq.question_set.count() > 0: question = kq.question_set.all()[0] kq_data['answered'] = 0 # if course.threshold is not None: # # if the course doesn't support certification, then don't # # return the 'passed' stat since it doesn't apply # kq_data['passed'] = 0 # for student in course.students.all(): # if calculate_kq_mark(kq, student) >= float(course.threshold): # kq_data['passed'] += 1 kq_data["viewed"] = activity.find({ "courses.%s.kqs" % course.id: str(kq.id) }).count() for question in kq.question_set.all(): kq_data["answered"] = answers.find({ "questions.%s" % question.id: { "$exists": True } }).count() data.append(kq_data) return HttpResponse(simplejson.dumps(data), mimetype='application/json')
def update_unit_mark(db, unit, user, threshold, new_mark_unit=None, new_mark_normalized_unit=None): from moocng.courses.marks import calculate_unit_mark if not new_mark_unit or not new_mark_normalized_unit: new_mark_unit, new_mark_normalized_unit = calculate_unit_mark(unit, user) data_unit = {} data_unit['user_id'] = user.pk data_unit['course_id'] = unit.course_id data_unit['unit_id'] = unit.pk marks_unit = db.get_collection('marks_unit') mark_unit_item = marks_unit.find_one(data_unit) if mark_unit_item: updated_unit_mark = (new_mark_unit != mark_unit_item['mark'] or new_mark_normalized_unit != mark_unit_item['relative_mark']) if updated_unit_mark: marks_unit.update( data_unit, {'$set': {'mark': new_mark_unit, 'relative_mark': new_mark_normalized_unit}}, safe=True ) else: updated_unit_mark = True data_unit['mark'] = new_mark_unit data_unit['relative_mark'] = new_mark_normalized_unit marks_unit.insert(data_unit) # check if user completed this unit unit_kqs = unit.knowledgequantum_set.all() completed = True for kq in unit_kqs: if not kq.is_completed(user): completed = False today = date.today() if completed: # badge unique unit badges = BadgeByCourse.objects.filter(course_id=unit.course_id, criteria_type=2, criteria=unit.id) for badge in badges: win = False if(badge.note <= new_mark_unit): gotBadge = get_db().get_collection('badge').find_one({'id_badge': badge.id, "id_user": user.pk}) if(not gotBadge): get_db().get_collection('badge').insert({"id_badge":badge.id, "id_user":user.pk, "title":badge.title, "description":badge.description, "color":badge.color, "date": today.isoformat()}) return updated_unit_mark, has_passed_now(new_mark_unit, mark_unit_item, threshold)
def kq_get_peer_review_score(kq, author, pra=None): """ppr_collection is peer_review_reviews mongo collection Return a tuple with (score, scorable) * If this kq isn't peer_review type: return (None, false) * If there is no submission: return (0, True) * If I haven't reviewed enough submissions of other students: return (0, True) * If nobody reviewed my submission: return (None, False) * If there are some reviews from other students to my submission but less than the minimum the teacher wants: return (Average, False) * If I got enough reviews of my submission and I have reviewed enough reviews of other students' submissions: rerturn (Average, True) """ if not pra: try: pra = kq.peerreviewassignment except PeerReviewAssignment.DoesNotExist: return (None, False) db = get_db() prs_collection = db.get_collection("peer_review_submissions") submission = prs_collection.find_one({"kq": kq.id, "author": author.id}) if not submission: return (0, True) if (submission.get("author_reviews", 0) < pra.minimum_reviewers): return (0, True) if (submission["reviews"] == 0): return (None, False) ppr_collection = db.get_collection("peer_review_reviews") reviews = ppr_collection.find({"kq": kq.id, "author": author.id}) reviews_count = reviews.count() sum_average = 0 for review in reviews: sum_average += float(get_peer_review_review_score(review)) average = sum_average / reviews_count if (submission["reviews"] > 0 and submission.get("author_reviews", 0) < pra.minimum_reviewers): return (average, False) else: return (average, True)
def on_activity_created_task(activity_created, unit_activity, course_activity): db = get_db() kq = KnowledgeQuantum.objects.get(id=activity_created['kq_id']) kq_type = kq.kq_type() course = Course.objects.get(id=activity_created['course_id']) logger.info(course.end_date) if date.today() < course.end_date: up_kq, up_u, up_c, passed_kq, passed_unit, passed_course = update_mark(activity_created) else: passed_kq = passed_unit = passed_course = False # KQ data = { 'viewed': 1 } if kq_type == 'Video' or passed_kq: data['passed'] = 1 stats_kq = db.get_collection('stats_kq') stats_kq.update( {'kq_id': activity_created['kq_id']}, {'$inc': data}, safe=True ) # UNIT data = {} if unit_activity == 1: # First activity of the unit data['started'] = 1 elif kq.unit.knowledgequantum_set.count() == unit_activity: data['completed'] = 1 if passed_unit: data['passed'] = 1 if data.keys(): stats_unit = db.get_collection('stats_unit') stats_unit.update( {'unit_id': kq.unit.id}, {'$inc': data}, safe=True ) # COURSE course_kqs = KnowledgeQuantum.objects.filter(unit__course__id=activity_created['course_id']).count() data = {} if course_activity == 1: # First activity of the course data['started'] = 1 elif course_kqs == course_activity: data['completed'] = 1 if passed_course: data['passed'] = 1 if data.keys(): stats_course = db.get_collection('stats_course') stats_course.update( {'course_id': activity_created['course_id']}, {'$inc': data}, safe=True )
def insert_blog_user(self, user_id, following, extra=None): user = { "id_user": user_id, "following": following } get_db().get_collection(self.col_user).insert(user) # xAPI if extra: user = User.objects.get(pk=user_id) course = None resource = { 'type': 'microblogfollow', 'user_id': extra['user_id'] } geolocation = extra.get('geolocation') x_api.learnerInteracts(user, resource, course, geolocation)
def handle(self, *args, **options): if not options["course_pk"]: raise CommandError("-c course_pk is required") groups = list(get_groups_by_course(options["course_pk"])) print "Groups: " + str(len(groups)) for group in groups: if "forum_slug" in group and group["forum_slug"] is not None: print "\nGroup " + str(group["name"]) + " already has forum topic" else: print "\nGroup " + str(group["name"]) + " has NO forum topic" course = Course.objects.filter(id=int(options["course_pk"]))[:1].get() split_result = re.split(r'([0-9]+)', course.forum_slug) cid = split_result[1] content = _(u"This is the topic for ") + group["name"] + _(u" where you can comment and help other team members") data = { "uid": 1, "title": group["name"], "content": content, "cid": cid } timestamp = int(round(time.time() * 1000)) authhash = hashlib.md5(settings.FORUM_API_SECRET + str(timestamp)).hexdigest() headers = { "Content-Type": "application/json", "auth-hash": authhash, "auth-timestamp": timestamp } if settings.FEATURE_FORUM: try: r = requests.post(settings.FORUM_URL + "/api2/topics", data=json.dumps(data), headers=headers) if r.status_code == requests.codes.ok: group["forum_slug"] = r.json()["slug"] mongodb.get_db().get_collection('groups').update({"_id": group["_id"]}, {"$set": {"forum_slug": group["forum_slug"]}}) print " --> Topic for Group '" + group["name"] + "' created succesfully." else: print " --> Could no create a topic for Group '" + group["name"] + "'. Server returns error code " + r.status_code + "." print r.text except: print " !!! Error creating course forum topic" print " Unexpected error:", sys.exc_info()
def post_edit(self, post_id, id_user, course_slug, postText): postCollection = get_db().get_collection(self.col_post) if self._can_edit(id_user, course_slug, post_id): postCollection.update({"_id": ObjectId(post_id)}, {"$set": {"text": escape(postText)}}) return True else: return False
def handle(self, *args, **options): all_courses_objs = Course.objects.only('id').all() all_courses_ids = [c.id for c in all_courses_objs] if options['all_courses']: courses = all_courses_objs elif not options['courses']: # FIXME this crashes, there are problems with the dates courses = Course.objects.only('id').filter(status='p').filter( # exclude courses that haven't started Q(start_date__is_null=True) | Q(start_date__is_null=False, start_date__lte=datetime.now)) if not options['finished_courses']: # exclude finished courses courses = courses.filter( Q(end_date__is_null=True) | Q(end_date__is_null=False, end_date__gte=datetime.now)) else: user_courses = options['courses'].split(',') courses = [] for id_or_slug in user_courses: try: if id_or_slug.isdigit(): c = Course.objects.only('id').get(id=id_or_slug) else: c = Course.objects.only('id').get(slug=id_or_slug) courses.append(c) except Course.DoesNotExist: print '"%s" does not exist' % id_or_slug pass courses = [c.id for c in courses] blacklist = [cid for cid in all_courses_ids if cid not in courses] print 'Calculating stats for these courses (ids): %s' % ', '.join( [str(cid) for cid in courses]) # Drop existing stats for selected courses db = get_db() stats_course = db.get_collection('stats_course') stats_unit = db.get_collection('stats_unit') stats_kq = db.get_collection('stats_kq') for cid in courses: stats_course.remove({'course_id': cid}, safe=True) stats_unit.remove({'course_id': cid}, safe=True) stats_kq.remove({'course_id': cid}, safe=True) # Callback to show some progress information def callback(step='', counter=0, total=0): step = max(1, int(total / 100)) if counter % step == 0: if step == 'calculating': print 'Processed %d of %d users' % (counter, total) elif step == 'storing': print 'Saved %d of %d statistics entries' % (counter, total) calculate_all_stats(callback=callback, course_blacklist=blacklist)
def handle(self, *args, **options): all_courses_objs = Course.objects.only('id').all() all_courses_ids = [c.id for c in all_courses_objs] if options['all_courses']: courses = all_courses_objs elif not options['courses']: # FIXME this crashes, there are problems with the dates courses = Course.objects.only('id').filter(status='p').filter( # exclude courses that haven't started Q(start_date__is_null=True) | Q(start_date__is_null=False, start_date__lte=datetime.now) ) if not options['finished_courses']: # exclude finished courses courses = courses.filter( Q(end_date__is_null=True) | Q(end_date__is_null=False, end_date__gte=datetime.now) ) else: user_courses = options['courses'].split(',') courses = [] for id_or_slug in user_courses: try: if id_or_slug.isdigit(): c = Course.objects.only('id').get(id=id_or_slug) else: c = Course.objects.only('id').get(slug=id_or_slug) courses.append(c) except Course.DoesNotExist: print '"%s" does not exist' % id_or_slug pass courses = [c.id for c in courses] blacklist = [cid for cid in all_courses_ids if cid not in courses] print 'Calculating stats for these courses (ids): %s' % ', '.join([str(cid) for cid in courses]) # Drop existing stats for selected courses db = get_db() stats_course = db.get_collection('stats_course') stats_unit = db.get_collection('stats_unit') stats_kq = db.get_collection('stats_kq') for cid in courses: stats_course.remove({'course_id': cid}, safe=True) stats_unit.remove({'course_id': cid}, safe=True) stats_kq.remove({'course_id': cid}, safe=True) # Callback to show some progress information def callback(step='', counter=0, total=0): step = max(1, int(total / 100)) if counter % step == 0: if step == 'calculating': print 'Processed %d of %d users' % (counter, total) elif step == 'storing': print 'Saved %d of %d statistics entries' % (counter, total) calculate_all_stats(callback=callback, course_blacklist=blacklist)
def course_stats(sender, instance, created, **kwargs): if created: stats_course = get_db().get_collection('stats_course') stats_course.insert({ 'course_id': instance.id, 'started': 0, 'completed': 0, 'passed': 0, }, data=True)
def post_delete(self, post_id, id_user, course_slug, avoidCascade=None): postCollection = get_db().get_collection(self.col_post) if self._can_edit(id_user, course_slug, post_id): if avoidCascade and len(postCollection.find({"_id": ObjectId(post_id)})[0]['children']) > 0: return False postCollection.update({"_id": ObjectId(post_id)}, {"$set": {"deleted": True}}) return True else: return False
def dispatch(self, request_type, request, **kwargs): # We need the request to dehydrate some fields try: question_id = int(request.GET.get("question", None)) except ValueError: raise BadRequest("question filter isn't a integer value") collection = get_db().get_collection("answers") self.answer = collection.find_one({"user_id": request.user.id, "question_id": question_id}) return super(OptionResource, self).dispatch(request_type, request, **kwargs)
def get_course_mark(course, user, db=None): data_course = {'user_id': user.pk, 'course_id': course.pk} db = db or get_db() marks_course = db.get_collection('marks_course') mark_course_item = marks_course.find_one(data_course) if mark_course_item: total_mark = mark_course_item['mark'] else: total_mark = 0 return (total_mark, get_units_info_from_course(course, user, db=db))
def kq_visited_by(self, user): db = get_db() activity = db.get_collection("activity") # Verify if user has watch the video from kq user_activity_exists = activity.find({ "user_id": user.id, "kq_id": self.id, }) return user_activity_exists.count() > 0
def insert_p2p_if_does_not_exists_or_raise(p2p_submission, submissions=None): if submissions is None: db = get_db() submissions = db.get_collection("peer_review_submissions") if submissions.find({ 'kq': p2p_submission['kq'], 'author': p2p_submission['author'] }).count() > 0: raise BadRequest( _('You have already sent a submission. Please reload the page')) return submissions.insert(p2p_submission)
def update_course_mark_by_user(course, user): db = mongodb.get_db() for unit in course.unit_set.scorables(): for kq in unit.knowledgequantum_set.all(): updated_kq, passed_kq_now = update_kq_mark(db, kq, user, course.threshold) update_passed(db, 'stats_kq', passed_kq_now, {'kq_id': kq.pk}) updated_unit, passed_unit_now = update_unit_mark( db, unit, user, course.threshold) update_passed(db, 'stats_unit', passed_unit_now, {'unit_id': unit.pk}) updated_course, passed_course_now = update_course_mark(db, course, user) update_passed(db, 'stats_course', passed_course_now, {'course_id': course.pk})
def forwards(self, orm): "Write your forwards methods here." from moocng.mongodb import get_db db = get_db() marks_course = db.get_collection('marks_course') marks_unit = db.get_collection('marks_unit') marks_kq = db.get_collection('marks_kq') marks_course.create_index([('course_id', pymongo.ASCENDING), ('user_id', pymongo.ASCENDING)]) marks_unit.create_index([('course_id', pymongo.ASCENDING), ('user_id', pymongo.ASCENDING)]) marks_kq.create_index([('unit_id', pymongo.ASCENDING), ('user_id', pymongo.ASCENDING)])
def dispatch(self, request_type, request, **kwargs): # We need the request to dehydrate some fields try: question_id = int(request.GET.get("question", None)) except ValueError: raise BadRequest("question filter isn't a integer value") collection = get_db().get_collection('answers') self.answer = collection.find_one({ "user_id": request.user.id, "question_id": question_id }) return super(OptionResource, self).dispatch(request_type, request, **kwargs)
def create_activity(self, user, kq): key = 'courses' course_id = str(kq.unit.course.id) activity_collection = get_db().get_collection('activity') user_data = activity_collection.find_one({'user': user.id}, safe=True) if user_data is None or not (key in user_data or course_id in user_data[key]): initial = {course_id: {'kqs': []}} user_data = {'user': user.id, key: initial} user_data['_id'] = activity_collection.insert(user_data) user_data[key][course_id]['kqs'] = [str(kq.id)] else: user_data[key][course_id]['kqs'].append(str(kq.id)) activity_collection.update({'_id': user_data['_id']}, user_data)
def calculate_question_mark(kq, question, user): db = get_db() answers = db.get_collection('answers') user_answer = answers.find_one({ 'user_id': user.id, 'question_id': question.id }) if user_answer: if user_answer and question.is_correct(user_answer): return (10.0, True) else: return (0.0, True) return (0.0, True)
def forwards(self, orm): kq_unit = {} for course in orm['courses.course'].objects.all(): for unit in course.unit_set.all(): for kq in unit.knowledgequantum_set.all(): kq_unit[str(kq.id)] = unit.id js_migration = """ var kq_unit = %s; db.activity_tmp.drop(); db.activity.find().forEach(function (activity) { var internal_counter = 0, course; for (cp in activity.courses) { course = activity.courses[cp]; internal_counter += course.kqs.length; course.kqs.forEach(function (kq) { db.activity_tmp.insert({ user_id: parseInt(activity.user, 10), course_id: parseInt(cp, 10), kq_id: parseInt(kq, 10), unit_id: kq_unit[kq] }); }); } }); """ % simplejson.dumps(kq_unit) connector = get_db() db = connector.get_database() db.eval(Code(js_migration)) db.activity.drop() try: db.activity_tmp.rename('activity') except OperationFailure: # if the activity collection was empty, then there is no new # collection to rename, but that is okay pass print "Activity collection migrated, old collection dropped. Creating indexes..." db.activity.create_index([("user_id", pymongo.ASCENDING), ("unit_id", pymongo.ASCENDING), ("kq_id", pymongo.ASCENDING)]) db.activity.create_index([("kq_id", pymongo.ASCENDING)])
def is_completed(self, user, visited=None): db = get_db() if visited is None: visited = self.kq.kq_visited_by(user) if not visited: return False # Verify if user has answered the question answers = db.get_collection("answers") answer_exists = answers.find_one({ "user_id": user.id, "question_id": self.id, }) return not (answer_exists is None)
def unit_stats(sender, instance, created, **kwargs): stats_unit = get_db().get_collection('stats_unit') if created: stats_unit.insert({ 'course_id': instance.course.id, 'unit_id': instance.id, 'started': 0, 'completed': 0, 'passed': 0, }, safe=True) else: stats_unit.update( {'unit_id': instance.id}, {'$set': {'course_id': instance.course.id}}, safe=True )
def calculate_question_mark(kq, question, user): """ Calculate if the user answer is the correct one, and punctuate accordingly. If the user did the task right the platform gives a 10, if not, a 0. .. versionadded:: 0.1 """ db = get_db() answers = db.get_collection('answers') user_answer = answers.find_one({ 'user_id': user.id, 'question_id': question.id }) if user_answer: if user_answer and question.is_correct(user_answer): return 10.0 return 0.0
def calculate_kq_mark(kq, user): # TODO Optimize per student from moocng.courses.models import Question from moocng.peerreview.models import PeerReviewAssignment from moocng.peerreview.utils import kq_get_peer_review_score try: db = get_db() question = Question.objects.filter(kq=kq) if question: answers = db.get_collection('answers') user_answer_list = answers.find_one({'user': user.id}, safe=True) if user_answer_list is not None: answer = user_answer_list.get('questions', {}).get(unicode(question[0].id)) if answer and question[0].is_correct(answer): return (10.0, True) else: if kq.unit.deadline is not None and kq.unit.deadline > datetime.now( kq.unit.deadline.tzinfo): return (0.0, True) else: peer_review_assignment = PeerReviewAssignment.objects.filter(kq=kq) if peer_review_assignment: mark, use_in_total = kq_get_peer_review_score( kq, user, peer_review_assignment[0]) if mark is not None: return (mark * 2.0, use_in_total ) # * 2 due peer_review range is 1-5 else: return (None, False) else: activity = db.get_collection('activity') user_activity_list = activity.find_one({'user': user.id}, safe=True) if user_activity_list is not None: visited_kqs = user_activity_list.get('courses', {}).get( unicode(kq.unit.course.id), {}).get('kqs', []) if unicode(kq.id) in visited_kqs: return (10.0, True) else: if kq.unit.deadline is not None and kq.unit.deadline > datetime.now( kq.unit.deadline.tzinfo): return (0, True) except AttributeError: pass return (0, True)
def on_activity_created_task(activity_created, unit_activity, course_activity): db = get_db() kq = KnowledgeQuantum.objects.get(id=activity_created['kq_id']) kq_type = kq.kq_type() up_kq, up_u, up_c, passed_kq, passed_unit, passed_course = update_mark( activity_created) # KQ data = {'viewed': 1} if kq_type == 'Video' or passed_kq: data['passed'] = 1 stats_kq = db.get_collection('stats_kq') stats_kq.update({'kq_id': activity_created['kq_id']}, {'$inc': data}, safe=True) # UNIT data = {} if unit_activity == 1: # First activity of the unit data['started'] = 1 elif kq.unit.knowledgequantum_set.count() == unit_activity: data['completed'] = 1 if passed_unit: data['passed'] = 1 if data.keys(): stats_unit = db.get_collection('stats_unit') stats_unit.update({'unit_id': kq.unit.id}, {'$inc': data}, safe=True) # COURSE course_kqs = KnowledgeQuantum.objects.filter( unit__course__id=activity_created['course_id']).count() data = {} if course_activity == 1: # First activity of the course data['started'] = 1 elif course_kqs == course_activity: data['completed'] = 1 if passed_course: data['passed'] = 1 if data.keys(): stats_course = db.get_collection('stats_course') stats_course.update({'course_id': activity_created['course_id']}, {'$inc': data}, safe=True)
def course_completed_started(course): activity = get_db().get_collection('activity') total_kqs = KnowledgeQuantum.objects.filter(unit__course=course).count() kqs_by_user = activity.group(condition={"course_id": course.id}, key={"user_id": 1}, initial={"kqs": 0}, reduce=Code("""function (curr, result) { result.kqs += 1 }""")) def is_completed(e): return e.get("kqs", 0) == total_kqs completed = len(filter(is_completed, kqs_by_user)) started = len(kqs_by_user) return (completed, started)
def unit_completed_started(unit): activity = get_db().get_collection('activity') total_kqs = unit.knowledgequantum_set.count() kqs_by_user = activity.group(condition={"unit_id": unit.id}, key={"user_id": 1}, initial={"kqs": 0}, reduce=Code("""function (curr, result) { result.kqs += 1 }""")) def is_completed(e): return e.get("kqs", 0) == total_kqs completed = len(filter(is_completed, kqs_by_user)) started = len(kqs_by_user) return (completed, started)
def on_activity_created(sender, user_id, mongo_object, **kwargs): api_task_logger.debug("activity created") data = mongo_object.to_dict() activity = get_db().get_collection('activity') unit_activity = activity.find({ 'user_id': data['user_id'], 'unit_id': data['unit_id'], }).count() course_activity = activity.find({ 'user_id': data['user_id'], 'course_id': data['course_id'] }).count() on_activity_created_task.apply_async( args=[data, unit_activity, course_activity], queue='stats', )
def update_mark(submitted): from moocng.courses.marks import calculate_kq_mark, calculate_unit_mark, calculate_course_mark updated_kq_mark = updated_unit_mark = updated_course_mark = False passed_kq = passed_unit = passed_course = False kq = KnowledgeQuantum.objects.get(pk=submitted['kq_id']) unit = kq.unit course = kq.unit.course user = User.objects.get(pk=submitted['user_id']) mark_kq, mark_normalized_kq = calculate_kq_mark(kq, user) db = get_db() # KQ updated_kq_mark, passed_kq = update_kq_mark( db, kq, user, course.threshold, new_mark_kq=mark_kq, new_mark_normalized_kq=mark_normalized_kq) # UNIT if not updated_kq_mark: return (updated_kq_mark, updated_unit_mark, updated_course_mark, passed_kq, passed_unit, passed_course) mark_unit, mark_normalized_unit = calculate_unit_mark(kq.unit, user) updated_unit_mark, passed_unit = update_unit_mark( db, unit, user, course.threshold, new_mark_unit=mark_unit, new_mark_normalized_unit=mark_normalized_unit) # COURSE if not updated_unit_mark: return (updated_kq_mark, updated_unit_mark, updated_course_mark, passed_kq, passed_unit, passed_course) mark_course, units_info = calculate_course_mark(unit.course, user) updated_course_mark, passed_course = update_course_mark( db, course, user, mark_course) return (updated_kq_mark, updated_unit_mark, updated_course_mark, passed_kq, passed_unit, passed_course)
def kq_get_peer_review_score(kq, author, pra=None): """ppr_collection is peer_review_reviews mongo collection Return a tuple with (score, scorable) * If this kq isn't peer_review type: return None * If there is no submission: return 0 * If I haven't reviewed enough submissions of other students: return 0 * If nobody reviewed my submission: return None * If I got enough reviews of my submission and I have reviewed enough reviews of other students' submissions: rerturn Average """ if not pra: try: pra = kq.peerreviewassignment except PeerReviewAssignment.DoesNotExist: return None db = get_db() prs_collection = db.get_collection("peer_review_submissions") submission = prs_collection.find_one({"kq": kq.id, "author": author.id}) if (not submission or submission.get("author_reviews", 0) < pra.minimum_reviewers): return 0 elif submission["reviews"] == 0: return None ppr_collection = db.get_collection("peer_review_reviews") reviews = ppr_collection.find({"kq": kq.id, "author": author.id}) reviews_count = reviews.count() sum_average = 0 for review in reviews: sum_average += float(get_peer_review_review_score(review)) return (sum_average / reviews_count) * 2 # * 2 due peer_review range is 1-5
def clone_activity_user_course(user, copy_course, original_course=None, force_email=False): if not original_course: original_course = copy_course.created_from if not original_course: raise ValueError("This course needs a original course") try: course_student_relation = user.coursestudent_set.get( course=copy_course) except CourseStudent.DoesNotExist: return ([], [], []) file_name = get_trace_clone_file_name(original_course, copy_course) file_path = get_trace_clone_file_path(file_name) f = open(file_path) trace_ids = json.loads(f.read()) f.close() if not copy_course.pk == trace_ids['Course'][str(original_course.pk)]: raise ValueError mongo_db = mongodb.get_db() new_act_docs = _clone_activity_user_course(mongo_db, trace_ids, user, copy_course, original_course) insert_answer_docs, update_answer_docs = _clone_answer_user_course( mongo_db, trace_ids, user, copy_course, original_course) if (new_act_docs or insert_answer_docs or update_answer_docs or course_student_relation.old_course_status != 'c' or force_email): if course_student_relation.old_course_status != 'c': course_student_relation.old_course_status = 'c' course_student_relation.save() if not settings.DEBUG: send_cloned_activity_email(original_course, copy_course, user) update_course_mark_by_user(copy_course, user) return (new_act_docs, insert_answer_docs, update_answer_docs)
def pending_reviews(peer_review_assignment, user, course, user_submissions): db = get_db() peer_review_reviews = db.get_collection('peer_review_reviews') reviewed = peer_review_reviews.find({ 'reviewer': user.id, 'kq': peer_review_assignment.kq.id, }) peer_review_submissions = db.get_collection('peer_review_submissions') assigned = peer_review_submissions.find({ 'assigned_to': user.id, 'kq': peer_review_assignment.kq.id, }) pending = peer_review_assignment.minimum_reviewers - reviewed.count() has_sent_submission = peer_review_assignment.id in user_submissions return { 'reviewed': reviewed, 'assigned': assigned, 'pending': pending, 'has_sent_submission': has_sent_submission, 'peer_review_assignment_id': peer_review_assignment.id, 'course_slug': course.slug }
def is_completed(self, user, visited=None): db = get_db() if visited is None: visited = self.kq.kq_visited_by(user) if not visited: return False # Verify if user has sent a submission submissions = db.get_collection("peer_review_submissions") user_submission = submissions.find_one({ "kq": self.kq.id, "author": user.id }) if not user_submission: return False if user_submission.get("author_reviews", 0) < self.minimum_reviewers: return False return True
def kq_stats(sender, instance, created, **kwargs): stats_kq = get_db().get_collection('stats_kq') if created: stats_kq.insert({ 'course_id': instance.unit.course.id, 'unit_id': instance.unit.id, 'kq_id': instance.id, 'viewed': 0, 'submitted': 0, 'reviews': 0, 'reviewers': 0, 'passed': 0, }, safe=True) # It doesn't matter if it has all the fields because the teacheradmin # view only returns the proper fields depending on the kq type else: stats_kq.update( {'kq_id': instance.id}, {'$set': { 'course_id': instance.unit.course.id, 'unit_id': instance.unit.id, }}, safe=True )