def _set_up_tasks(self): # TODO: add base test for model with userprofiles. self.admin = User.objects.get(id=1) self.alice = User.objects.get(id=2) content1 = MathContent.objects.create(text="Test text for the task1") content2 = MathContent.objects.create(text="Test text for the task2") self.admin_task = Task.objects.create(name="First", content=content1, author=self.admin, hidden=True) self.alice_task = Task.objects.create(name="Second", content=content2, author=self.alice, hidden=True) set_tags(self.admin_task, ["IMO", "geo"]) set_tags(self.alice_task, ["MEMO", "alg"])
def create_tasks_from_json(description): """ Given a list of Task description dictionaries, create Task instances, together with other related objects. Supported special data: _content (string) - the text of the task, MathContent text _folder_id (int) - ID of the folder where to add the task _folder_position (int) - position in that folder _tags (string) - a comma-separated list of tags _difficulty (int) - difficulty rating to be assigned by the author _permissions (dict {"permission type ID": [list of group IDs]}) - group permission to automatically assign. - (ID is a string because in JSON keys must be strings) All other elements with an underscore are ignored. Params: description (list): list of dict object, describing the tasks Returns: A list of the new Task objects. If an exception is thrown in the middle of the process, the exception is caputed, the message changed, and raised again. """ # Approx. task_fields = set(Task._meta.get_all_field_names()) task_fields |= set(x + '_id' for x in task_fields) created_objects = [] created_tasks = [] message_list = [] # List of objects to create folder_tasks = [] object_permissions = [] try: for k, desc in enumerate(description): message_list.append('Creating {}. task...'.format(k + 1)) # First, prepare data to be able to create Task. # --- math content --- math_content = MathContent() math_content.text = desc['_content'] message_list.append(desc['_content']) math_content.save() created_objects.append(math_content) # Second, create Task. task = Task() task.content = math_content for key, value in desc.iteritems(): if key[0] != '_' and key in task_fields: setattr(task, key, value) task.save() created_objects.append(task) created_tasks.append(task) # Third, save other data. # --- tags --- tags = desc.get('_tags', '') set_tags(task, tags) # --- difficulty --- difficulty = desc.get('_difficulty') if difficulty: task.difficulty_rating.update(task.author, int(difficulty)) # --- folder ids --- folder_id = desc.get('_folder_id') if folder_id is not None: folder_tasks.append(FolderTask( folder_id=folder_id, task=task, position=desc.get('_folder_position', 0))) # --- group permissions --- for perm, group_ids in desc.get('_permissions', {}).iteritems(): for group_id in group_ids: object_permissions.append(ObjectPermission( content_object=task, group_id=group_id, permission_type=perm)) FolderTask.objects.bulk_create(folder_tasks) ObjectPermission.objects.bulk_create(object_permissions) except Exception as e: # This should remove all dependend objects. for obj in created_objects: obj.delete() message_list.append("Reverting changes...") message = "\n".join(message_list) + "\n\n" + traceback.format_exc() raise type(e)(message) finally: # SPEED: Don't invalidate everything. invalidate_cache_for_folders(Folder.objects.all()) return created_tasks
def new(request, task_id=None, is_file=None, is_lecture=None): """ New Task and Edit Task + New TaskFile and Edit TaskFile """ content_type = ContentType.objects.get_for_model(Task) if task_id: task = get_object_or_404(Task.objects.select_related('content'), pk=task_id) perm = task.get_user_permissions(request.user) if EDIT not in perm: return 403 math_content = task.content edit = True is_file = task.is_file() is_lecture = task.is_lecture else: perm = [] task = math_content = None edit = False # Make sure each lecture is a file. assert is_lecture and is_file or not is_lecture form_class = TaskLectureForm if is_lecture \ else (TaskFileForm if is_file else TaskForm) math_content_label = 'Opis' if is_file else None # else default if request.method == 'POST': old_hidden = getattr(task, 'hidden', -1) old_solvable = getattr(task, 'solvable', -1) # Files can have blank description (i.e. math content) task_form = form_class(request.POST, instance=task, user=request.user) math_content_form = MathContentForm(request.POST, instance=math_content, blank=is_file, label=math_content_label, auto_preview=False) attachment_form = is_file and not edit \ and AttachmentForm(request.POST, request.FILES) if task_form.is_valid() and math_content_form.is_valid() \ and (not attachment_form or attachment_form.is_valid()): task = task_form.save(commit=False) math_content = math_content_form.save() if not edit: if attachment_form: attachment, attachment_form = check_and_save_attachment( request, math_content) task.file_attachment = attachment # This is a file. path = attachment.get_full_path_and_filename() try: thumbnail_path = create_file_thumbnail(path) task.cache_file_attachment_thumbnail_url = \ media_path_to_url(thumbnail_path) except ThumbnailRenderingException: pass # Immediately remember file url, so that we don't have to # access Attachment table to show the link. task.cache_file_attachment_url = attachment.get_url() else: task.file_attachment = None # This is a task. if is_file: task.cache_file_attachment_url = task.file_attachment.get_url() if not edit: task.author = request.user task.content = math_content task.save() # Do not call task_form.save_m2m()! set_tags(task, task_form.cleaned_data['tags']) # TODO: signals! if not edit or old_hidden != task.hidden \ or old_solvable != task.solvable: \ invalidate_folder_cache_for_task(task) # send action if creating a new nonhidden task if not edit: # TODO: signals! type = _action.LECTURE_ADD if is_lecture \ else (_action.FILE_ADD if is_file else _action.TASK_ADD) _action.add(request.user, type, action_object=task, target=task) # TODO: izbrisati task_new_finish.html i url #return HttpResponseRedirect('/task/%d/' % task.id if edit else '/task/new/finish/') return HttpResponseRedirect(task.get_absolute_url()) else: task_form = form_class(instance=task) math_content_form = MathContentForm(instance=math_content, blank=is_file, label=math_content_label, auto_preview=False) attachment_form = is_file and not edit and AttachmentForm() forms = [task_form, math_content_form] if attachment_form: forms.append(attachment_form) data = get_task_folder_data(task, request.user) if task else {} data.update({ 'action_url': request.path, 'bulk_add_url': '/task/new/bulk/', 'can_edit_permissions': EDIT_PERMISSIONS in perm, 'content_type': content_type, 'edit': edit, 'forms': forms, 'is_file': is_file, 'is_lecture': is_lecture, 'lectures_folder_url': settings.LECTURES_FOLDER_URL, 'task_name': task.name if task else None, # Convenience. 'task': task, }) return data
def _create_task(author, tags, hidden): content = MathContent.objects.create(text="Test text", html="Test text") task = Task.objects.create(name="Test task", content=content, author=author, hidden=hidden) set_tags(task, tags) return task
def _create_folders(author, parent, structure, p): vars = {'p': p} level, separator, rest = structure.partition('|') rest = rest.strip() # Split the level description into lines, remove trailing and leading # whitespaces, and remove empty lines lines = filter(None, [x.strip() for x in level.strip().split('\n')]) # Child format defined in the first line # Format: var_name1/var_name2/.../var_nameN var_names = [x.strip() for x in lines[0].split('/')] # Evaluate variables in specified order, don't shuffle them! var_formats = [] # List of children tuples children = [] # Skip first line! for x in lines[1:]: left, separator, right = x.partition('=') if separator: # Variable definition: var_name=this is a example number {x} var_formats.append((left, right)) elif left[0] == '%': # Special command if left.startswith('%RANGE'): # E.g. %RANGE 2012, 1996 # --> Adds children: 2012, 2011, ..., 1997, 1996 a, b = [int(x) for x in left[6:].split(',')] r = range(a, b + 1) if a <= b else range(a, b - 1, -1) children.extend([str(x) for x in r]) else: raise Exception('Nepoznata naredba: ' + left) else: # Child definition: var_value1/var_value2/.../var_valueN children.append(left) created = 0 existing = 0 for index, x in enumerate(children): # Update vars with child var values. (values are stripped!) vars.update({k: v.strip() for k, v in zip(var_names, x.split('/'))}) # Update additional vars for var in var_formats: # Note we are using same dictionary that is being updated, that's # why order matters vars[var[0]] = var[1].format(**vars) try: # Check if folder with the same name, short name and parent exists. folder = Folder.objects.get(parent=parent, name=vars['name'], short_name=vars['short']) existing += 1 except: # If not, create new folder. folder = Folder(author=author, parent=parent, parent_index=index, hidden=False, editable=False, name=vars['name'], short_name=vars['short']) folder.save() created += 1 # Note that the object has to exist to use this! set_tags(folder, vars['tags']) # TODO: call folder._refresh_cache_tags() on change signal. # Call recursion if there is any level left if rest: # Note that parent changed! _c, _e = _create_folders(author, folder, rest, _dict_to_object(vars)) created += _c existing += _e return created, existing
def new(request, folder_id=None): # Analogous to task.models.new if folder_id: folder = get_object_or_404(Folder, id=folder_id) edit = True old_parent_id = folder.parent_id else: folder = old_parent_id = None edit = False data = {} initial_parent_id = None if edit: if not folder.editable: return response.FORBIDDEN permissions = folder.get_user_permissions(request.user) if EDIT not in permissions: return response.FORBIDDEN if EDIT_PERMISSIONS in permissions: data['can_edit_permissions'] = True data['content_type'] = ContentType.objects.get_for_model(Folder) data['children'] = children = list(Folder.objects \ .for_user(request.user, VIEW) \ .filter(parent=folder).order_by('parent_index').distinct()) data['has_subfolders_strict'] = Folder.objects \ .filter(parent_id=folder_id).exists() else: referrer = get_referrer_path(request) if referrer and referrer.startswith('/folder/'): try: initial_parent_id = int(referrer[8:referrer.find('/', 8)]) except: pass if request.method == 'POST': folder_form = FolderForm(request.POST, instance=folder, user=request.user) if folder_form.is_valid(): folder = folder_form.save(commit=False) # TODO: Make a util function for creating Folder instances, to be # able to create tests easier. # If user can't edit short name, copy full name. if 'short_name' not in folder_form.fields: folder.short_name = folder.name if not edit: folder.author = request.user else: for x in children: parent_index = request.POST.get('child-{}'.format(x.id)) parent_index = int(parent_index) if parent_index is not None \ and x.parent_index != parent_index: x.parent_index = parent_index x.save() # Update order... children.sort(key=lambda x: x.parent_index) # If editing, refresh immediately before saving. # Do not call folder_form.save_m2m()! folder._no_save = True set_tags(folder, folder_form.cleaned_data['tags']) folder.save() if not edit: # If new, first save folder (and define ID), and then save tags. set_tags(folder, folder_form.cleaned_data['tags']) # Refresh Folder cache. if old_parent_id != folder.parent_id: # The only folders that have to be refreshed are those in # the folder's subtree, together with folder itself. descendant_ids = get_folder_descendant_ids(folder.id) descendant_ids.append(folder.id) # refresh_path_cache also requires ancestors. Following code # works, because you can't move a folder into its child folder. descendant_ids.extend([int(x) for x in folder.parent.cache_ancestor_ids.split(',') if x]) descendant_ids.append(folder.parent_id) refresh_path_cache(Folder.objects.filter(id__in=descendant_ids)) if not edit: return ('/folder/{}/edit/'.format(folder.id), ) # return HttpResponseRedirect(folder.get_absolute_url()) else: folder_form = FolderForm(instance=folder, user=request.user, initial_parent_id=initial_parent_id) # If parent given and acceptable, show menu. (new mode) initial_parent = getattr(folder_form, 'initial_parent', None) if initial_parent: data.update(prepare_folder_menu([initial_parent], request.user)) if edit: data.update(prepare_folder_menu([folder], request.user)) data['folder'] = folder data['form'] = folder_form data['edit'] = edit if request.user.has_perm('folder.advanced_create'): data['advanced_create_permission'] = True return data