예제 #1
0
def delete_race_and_ratings(race, *args, **kwargs):

	from rated_tree_modifications import make_temporary_clone
	# ^ here to aviod cyclic import ^

	assert type(race).__name__ == 'Race'

	log = logging.getLogger('structure_modification')
	log_prefix = 'race.delete(): id={}'.format(race.id)
	log.debug('{} before flock'.format(log_prefix))
	with Flock_mutex(LOCK_FILE_FOR_RATED_TREE_MODIFICATIONS):
		log.debug('{} trnsctn start'.format(log_prefix))
		try:
			with transaction.atomic():
				for overall_node in race.sr_overall.all():
					make_temporary_clone(overall_node, delete_original=True)
					# Linked Race_by_param, User_overall, User_by_param and corresponding *_update
					# instances will be deleted by CASCADE mechanism

				for group in race.group_set.all():
					group.delete()
					# Linked Group_new, Primary and User_review instances will be deleted
					# by CASCADE mechanism

				super(type(race), race).delete(*args, **kwargs)
			log.debug('{} trnsctn end'.format(log_prefix))
		except Exception as e:
			log.error('{} Unexpected error: {}'.format(log_prefix, repr(e)), exc_info=True)
			raise
		else:
			log.info('{} OK'.format(log_prefix))
예제 #2
0
def remove_series(request, organizer_id, series_id):
	organizer = get_object_or_404(models.Organizer, pk=organizer_id)
	if 'btnRemoveSeries' in request.POST:
		series = get_object_or_404(models.Series, pk=series_id)
		if series.organizer != organizer:
			messages.warning(request, u'У серии {} (id {}) и так не указан организатор {} (id {}).'.format(
					series.name, series_id, series.organizer.name, series.organizer.id))
		else:
			log = logging.getLogger('structure_modification')
			log_prefix = 'remove_series {} from organizer {} by user {}.'.format(series.id, organizer_id, request.user.id)
			log.debug('{} before flock'.format(log_prefix))
			log_exc_info = False
			with Flock_mutex(LOCK_FILE_FOR_RATED_TREE_MODIFICATIONS):
				log.debug('{} trnsctn start'.format(log_prefix))
				try:
					with transaction.atomic():
						change_parent(series, models.Organizer.objects.fake_object)
						# ^ to adapt the starrating data) ^
						series.organizer_id = models.FAKE_ORGANIZER_ID
						series.save()
						models.log_obj_create(request.user, series, models.ACTION_UPDATE, field_list=['organizer'])
					log.debug('{} trnsctn end'.format(log_prefix))
				except (UpdatedRecordExistsError, AssertionError) as e:
					error_msg = repr(e)
					if isinstance(e, AssertionError):
						log_exc_info = True
				else:
					error_msg = None
				if error_msg is None:
					log.info('{} OK'.format(log_prefix))
					messages.success(request, u'Серия «{}» (id {}) успешно отвязана от этого организатора.'.format(series.name, series_id))
				else:
					log.error('{} {}'.format(log_prefix, error_msg), exc_info=log_exc_info)
					messages.warning(request, u'Не удалось отвязать серию «{}» (id {}) от этого организатора ({}).'.format(series.name, series_id, error_msg))
	return redirect(organizer)
예제 #3
0
def create_all_zero_records_for_new_groups(
        method_ids=(), only_one_group=False, log=None):
    # print "create_all_zero_records_for_new_groups", method_ids
    assert isinstance(method_ids, (list, tuple))
    if log:
        pid = getpid()
        log.debug(
            'create_all_zero_records_for_new_groups[{}] start: methods_ids={}, only_one_group={},'
            .format(
                pid,
                method_ids,
                1 if only_one_group else 0,
            ))
    if not method_ids:
        method_ids = tuple(get_actual_methods())
        if log:
            log.debug('actual methods: {}'.format(method_ids))

    if log:
        group_id_list = []
        MAX_LIST_LENGTH = 100

    group_count = 0
    for group_id in Group_new.objects.all().values_list('id', flat=True):
        with Flock_mutex(LOCK_FILE_FOR_RATED_TREE_MODIFICATIONS):
            with transaction.atomic():
                for m_id in method_ids:
                    mk_aggr_structure_for_group(group_id, method_id=m_id)
                Group_new.objects.filter(id_id=group_id).delete()
        result = True
        group_count += 1
        if log:
            if group_count <= MAX_LIST_LENGTH:
                group_id_list.append(group_id)
        if only_one_group:
            break
    if log:
        log.debug(
            'create_all_zero_records_for_new_groups[{}] result: group_count={}'
            .format(
                pid,
                group_count,
            ))
        if group_count > 0:
            log.info('processed groups: {}{}'.format(
                ' '.join([str(x) for x in group_id_list]),
                ' ... {}'.format(group_id)
                if len(group_id_list) == MAX_LIST_LENGTH
                and group_id != group_id_list[-1] else ''))

    return group_count
예제 #4
0
def process_update_record(obj):
    """
	Requires:
	- на всех предыдущих уровнях уже посчитаны основые значения, _updated удалены
	- правильные by_param-значения для данного уровня уже записаны в _by_param_updated
	- если для overall данного уровня направление child - то их правильные значения
	  тоже уже записаны в _overall_updated
	  иначе, в _overall_updated могут (должны?) быть записаны NULL
	
	ДОДУМАЙ: user_count всегда вычисляется в направлении child!
	"""
    def copy_from_by_param_updated(overall_id, parameters):
        # TODO: копировать поля выборочно.
        sub_filter = by_param_updated_model.objects.filter(pk=OuterRef('pk'))
        by_param_model.objects.all().filter(
            overall_id=overall_id,
            parameter_id__in=parameters,
        ).update(
            sum_int=Subquery(sub_filter.values('sum_int')),
            sum_float=Subquery(sub_filter.values('sum_float')),
            user_count=Subquery(sub_filter.values('user_count')),
            weight=Subquery(sub_filter.values('weight')),
        )

    def copy_from_overall_updated(overall_id):
        # TODO: копировать поля выборочно
        sub_filter = overall_updated_model.objects.filter(pk=OuterRef('pk'))
        # print type(overall_id)
        overall_model.objects.all().filter(pk=overall_id).update(
            sum_int=Subquery(sub_filter.values('sum_int')),
            sum_float=Subquery(sub_filter.values('sum_float')),
            user_count=Subquery(sub_filter.values('user_count')),
            weight=Subquery(sub_filter.values('weight')),
        )

    def delete_overall_updated(overall_id):
        overall_updated_model.objects.filter(pk=overall_id).delete()

    def delete_by_param_updated(overall_id):
        by_param_updated_model.objects.filter(
            id__overall_id=overall_id).delete()

    def get_as_values(qs, fields=()):
        assert len(qs) == 1
        return qs.values(*fields)[0]

    ########################
    # End of sub-functions #
    ########################

    assert isinstance(obj, Overall_updated_abstract_model)
    print "process_update_record", obj
    level = level_of_model(type(obj))
    print "level=", level

    has_parent = (level + 1) in LEVEL_NO_TO_NAME

    ### Собираем модели и ids
    overall_updated_model = type(obj)
    overall_model = get_base_model(type(obj))
    by_param_updated_model = get_dependent_model(type(obj))
    by_param_model = get_base_model(by_param_updated_model)

    ov_id = obj.pk

    method_spec_this = get_methods_specification()[obj.id.method_id][level]

    if has_parent:
        overall_parent_model = type(obj.id.parent)
        by_param_parent_model = get_dependent_model(overall_parent_model)
        overall_parent_updated_model = get_upd_model(overall_parent_model)
        by_param_parent_updated_model = get_upd_model(by_param_parent_model)

        method_spec_parent = get_methods_specification()[obj.id.method_id][
            level + 1]
    """
	Надо в рамках транзакции
	* Вычисления на текущем уровне
		- by_param уже готов в _updated, вычислять не надо [НЕТ bp_current]
		- overall_updated:
			Если направление child, то уже готов в _updated, вычислять не надо
			Иначе их надо обновить на основе by_param_updated текущего уровня
			и результаты записать в _updated.    [ov_current]
	* Вычисления на уровне parent
		- by_param: обновить parent _updated.parent на основе текущего _update
			и записать результаты в parent _upated модель.   [pb_parent]
		- overall:
			- если направление указано child, аналогично предыдущему
			обновить parent _updated на основе текущего _update
			и записать результаты в parent _upated модель.
			- иначе создать parent _updated модель с NULL-значениями.
					Это все - [ov_parent]
	* скопировать by_param_updated и overall_updated в основную модель [copy_updated]
	* удалить by_param_updated и overall_updated (в любом порядке) [delete_updated]

	Зависимости:
		[delete_updated ov] after [copy_updated ov] after [ov_parent] after [ov_current]
		[delete_updated bp] after [copy_updated bp] after [bp_parent]
		Эти две цепочки могут выполнятся параллельно
			(зависимость ov_parent от bp_parent возможна, но в этом случае 
			реальные вычисления происходят на шаге, соответсвующим след. уровню.
			Поэтому здесь эту зависимость можно игнорировать)
	"""

    #####
    # считываем данные, с помощью которых будем апдейтить
    bp_data_fields = ('user_count', 'weight',
                      method_spec_this['by_param_field'])
    ov_data_fields = ('user_count', 'weight',
                      method_spec_this['overall_field'])

    if has_parent:
        bp_data_parent_fields = ('user_count', 'weight',
                                 method_spec_parent['by_param_field'])
        ov_data_parent_fields = ('user_count', 'weight',
                                 method_spec_parent['overall_field'])

    bp_new_data = queryset_to_dict(
        by_param_updated_model.objects.filter(id__overall_id=ov_id).values(
            'id__parameter_id', *bp_data_fields), 'id__parameter_id')
    par_list = tuple(bp_new_data.keys())

    by_param_qs = by_param_model.objects.filter(overall_id=ov_id,
                                                parameter_id__in=par_list)
    bp_old_data = queryset_to_dict(
        by_param_qs.values('parameter_id', *bp_data_fields), 'parameter_id')
    assert tuple(bp_old_data.keys()) == par_list

    if has_parent:
        bp_parent_records = queryset_to_dict(
            obj.id.parent.by_param.all().filter(parameter_id__in=par_list),
            'parameter_id'
        )  # will be a dict of model instances indexed by parameter id

    overall_qs = overall_model.objects.filter(pk=ov_id)
    ov_old_data = get_as_values(overall_qs, ov_data_fields)
    ov_new_data = get_as_values(
        overall_updated_model.objects.filter(id__pk=ov_id),
        ov_data_fields + ('to_delete', ),
    )

    # print "before transaction"
    with Flock_mutex(LOCK_FILE_FOR_RATED_TREE_MODIFICATIONS):
        with transaction.atomic():
            # overall sequence
            '''
			calc_overall_current(
				old_data=bp_old_data,
				new_data=bp_new_data,
				bp_sum_field_name=method_spec_this['by_param_field'],
				ov_sum_field_name=method_spec_this['overall_field'],
				calc_method=method_spec_this['overall_spec'],
				ov_record=obj,
				upd_model=overall_parent_updated_model,
				direction=method_spec_this['overall_dir'],
			)
			'''
            if has_parent:
                calc_overall_parent(
                    old_data=ov_old_data,
                    new_data=ov_new_data,
                    current_sum_field_name=method_spec_this['overall_field'],
                    parent_sum_field_name=method_spec_parent['overall_field'],
                    calc_method=method_spec_parent['overall_spec'],
                    parent_record=obj.id.parent,
                    upd_model=overall_parent_updated_model,
                    direction=method_spec_parent['overall_dir'])
            copy_from_overall_updated(ov_id)
            delete_overall_updated(ov_id)

            # by_param sequence
            if has_parent:
                calc_by_param_parent(
                    old_data=bp_old_data,
                    new_data=bp_new_data,
                    current_sum_field_name=method_spec_this['by_param_field'],
                    parent_sum_field_name=method_spec_parent['by_param_field'],
                    calc_method=method_spec_parent['by_param_spec'],
                    parent_records=bp_parent_records,
                    upd_model=by_param_parent_updated_model,
                )
            copy_from_by_param_updated(ov_id, par_list)
            delete_by_param_updated(ov_id)
            if ov_new_data['to_delete']:
                # assert all_zero(ov_new_data) # TODO
                # assert all_zero(bp_new_data)
                by_param_qs.delete()
                overall_qs.delete()
예제 #5
0
def organizer_delete(request, organizer_id):
	organizer = get_object_or_404(models.Organizer, pk=organizer_id)
	has_dependent_objects = organizer.has_dependent_objects()
	ok_to_delete = False
	if 'frmForOrganizer_submit' in request.POST:
		form = forms.ForOrganizerForm(request.POST, auto_id='frmForOrganizer_%s')
		if form.is_valid():
			if has_dependent_objects:
				organizer_for = form.cleaned_data['organizer']
				if organizer_for != organizer:
					ok_to_delete = True
				else:
					messages.warning(request, u'Нельзя заменить организатора на его самого.')
			else: # There are no dependent objects of the organizer, so we just delete it
				ok_to_delete = True
		else:
			messages.warning(request, u'Организатор не удалён. Пожалуйста, исправьте ошибки в форме.')
	else:
		form = None
		messages.warning(request, u'Вы не указали город для удаления.')
	if ok_to_delete:
		# NOT TESTED !
		if has_dependent_objects:
			organizer_for_id = organizer_for.id
		else:
			organizer_for_id = 0
			organizer_for = None
		log = logging.getLogger('structure_modification')
		log_prefix = 'organizer_delete: organizer {}->{}, by user {}.'.format(
			organizer_id, organizer_for_id, request.user.id
		)
		log_exc_info = False
		oranizer_name_full = organizer.name_full()
		log.debug('{} before flock'.format(log_prefix))
		with Flock_mutex(LOCK_FILE_FOR_RATED_TREE_MODIFICATIONS):
			try:
				with transaction.atomic():
					if has_dependent_objects:
						update_organizer(request, organizer, organizer_for)
					models.log_obj_delete(request.user, organizer)
					organizer.delete()
				log.debug('{} trnsctn end'.format(log_prefix))
			except (UpdatedRecordExistsError, AssertionError) as e:
				error_msg = repr(e)
				if isinstance(e, AssertionError):
					log_exc_info = True
			except Exception as e:
				log.error('{} Unexpected error: {}'.format(log_prefix, repr(e)), exc_info=True)
				raise
			else:
				error_msg = None
		if error_msg is None:
			log.info('{} OK'.format(log_prefix))
			messages.success(request, u'Организатор «{}» успешно удалён.'.format(organizer_name_full))
		else:
			log.error('{} {}'.format(log_prefix, error_msg), exc_info=log_exc_info)
			messages.warning(
				request, u'Не удалось удалить организатора «{}» ({}).'.format(
					organizer_name_full, error_msg
				)
			)
		if has_dependent_objects:
			return redirect(organizer_for.get_editor_url())
		else:
			return redirect('editor:organizer_create')
	return organizer_details(request, organizer_id=organizer_id)
예제 #6
0
def series_delete(request, series_id):
    series = get_object_or_404(models.Series, pk=series_id)
    context, has_rights, target = check_rights(request, series=series)
    if not has_rights:
        return target
    has_dependent_objects = series.has_dependent_objects()
    ok_to_delete = False

    if (request.method == 'POST') and request.POST.get('frmForSeries_submit',
                                                       False):
        form = forms.ForSeriesForm(request.POST, auto_id='frmForSeries_%s')
        if form.is_valid():
            if has_dependent_objects:
                new_series_id = models.int_safe(
                    request.POST.get('new_series_id', 0))
                if new_series_id:
                    if new_series_id != series.id:
                        new_series = models.Series.objects.filter(
                            pk=new_series_id).first()
                        if new_series:
                            ok_to_delete = True
                        else:
                            messages.warning(
                                request,
                                u'Серия, на которую нужно заменить текущую, не найдена.'
                            )
                    else:
                        messages.warning(request,
                                         u'Нельзя заменить серию на неё же.')
                else:
                    messages.warning(
                        request,
                        u'Серия, на которую нужно заменить текущую, не указана.'
                    )
            else:  # There are no events in the series, so we just delete it
                ok_to_delete = True
        else:
            messages.warning(
                request,
                u"Серия не удалена. Пожалуйста, исправьте ошибки: {}".format(
                    form.errors))
    else:
        form = forms.ForSeriesForm(auto_id='frmForSeries_%s')
        messages.warning(request, u"Вы не указали серию для удаления.")

    if ok_to_delete:
        if not has_dependent_objects:
            new_series_id = 0
            new_series = None
        log = logging.getLogger('structure_modification')
        log_prefix = 'series_delete: series {}->{}, by user {}.'.format(
            series_id, new_series_id, request.user.id)
        log_exc_info = False
        log.debug('{} before flock'.format(log_prefix))
        with Flock_mutex(LOCK_FILE_FOR_RATED_TREE_MODIFICATIONS):
            try:
                with transaction.atomic():
                    if has_dependent_objects:
                        update_series(request, series, new_series)
                    transfer_children_before_node_deletion(series, new_series)
                    models.log_obj_delete(request.user, series)
                    series.delete()
                log.debug('{} trnsctn end'.format(log_prefix))
            except (UpdatedRecordExistsError, AssertionError) as e:
                error_msg = repr(e)
                if isinstance(e, AssertionError):
                    log_exc_info = True
            except Exception as e:
                log.error('{} Unexpected error: {}'.format(
                    log_prefix, repr(e)),
                          exc_info=True)
                raise
            else:
                error_msg = None
        if error_msg is None:
            log.info('{} OK'.format(log_prefix))
            messages.success(request,
                             u'Серия «{}» успешно удалена.'.format(series))
        else:
            log.error('{} {}'.format(log_prefix, error_msg),
                      exc_info=log_exc_info)
            messages.warning(
                request, u'Не удалось удалить серию «{}» ({}).'.format(
                    series, error_msg))

        if has_dependent_objects:
            return redirect(new_series)
        else:
            return redirect('results:races')

    return series_details(request,
                          series_id=series_id,
                          series=series,
                          frmForSeries=form)
예제 #7
0
def event_delete(request, event_id):
	event = get_object_or_404(models.Event, pk=event_id)
	context, has_rights, target = check_rights(request, event=event)
	if not has_rights:
		return target
	has_dependent_objects = event.has_dependent_objects()
	ok_to_delete = False
	if 'frmForEvent_submit' in request.POST:
		form = forms.ForEventForm(request.POST, auto_id='frmForEvent_%s')
		if form.is_valid():
			if has_dependent_objects:
				new_event_id = models.int_safe(request.POST.get('new_event_id', 0))
				if new_event_id:
					if new_event_id != event.id:
						new_event = models.Event.objects.filter(pk=new_event_id).first()
						if new_event:
							ok_to_delete = True
						else:
							messages.warning(request, u'Забег, на который нужно заменить текущий, не найден.')
					else:
						messages.warning(request, u'Нельзя заменить забег на себя же.')
				else:
					messages.warning(request, u'Забег, на который нужно заменить текущий, не указан.')
			else: # There are no races in the event, so we just delete it
				ok_to_delete = True
		else:
			messages.warning(request, u"Забег не удалён. Пожалуйста, исправьте ошибки в форме.")
	else:
		form = None
		messages.warning(request, u"Вы не указали забег для удаления.")
	if ok_to_delete:
		if not has_dependent_objects:
			new_event_id = 0
			new_event = None
		log = logging.getLogger('structure_modification')
		log_prefix = 'event_delete: event {}->{}, by user {}.'.format(event_id, new_event_id, request.user.id)
		log.debug('{} before flock'.format(log_prefix))
		log_exc_info = False
		with Flock_mutex(LOCK_FILE_FOR_RATED_TREE_MODIFICATIONS):
			event_name = event.name
			series = event.series
			log.debug('{} trnsctn start'.format(log_prefix))
			try:
				with transaction.atomic():
					if has_dependent_objects:
						update_event(request, event, new_event)
					log.debug('{} 1'.format(log_prefix))
					transfer_children_before_node_deletion(event, new_event)
					log.debug('{} 2'.format(log_prefix))
					models.log_obj_delete(request.user, event)
					log.debug('{} 3'.format(log_prefix))
					start_date = event.start_date
					event.delete()
					log.debug('{} 4'.format(log_prefix))
					update_events_count()
					log.debug('{} 5'.format(log_prefix))
					update_course_records(series)
					if event.series.is_russian_parkrun():
						log.debug('{} 6'.format(log_prefix))
						prev_event = series.event_set.filter(start_date__lt=start_date).order_by('-start_date').first()
						if prev_event:
							_, n_fixed_parkruns = views_parkrun.fix_parkrun_numbers(correct_event=prev_event)
							messages.success(request, u'Исправлена нумерация у {} паркран{} после удалённого'.format(n_fixed_parkruns,
								results_util.plural_ending_new(n_fixed_parkruns, 1)))
				log.debug('{} trnsctn end'.format(log_prefix))
			except (UpdatedRecordExistsError, AssertionError) as e:
				error_msg = repr(e)
				if isinstance(e, AssertionError):
					log_exc_info = True
			except Exception as e:
				log.error('{} Unexpected error: {}'.format(log_prefix, repr(e)), exc_info=True)
				raise
			else:
				error_msg = None
		if error_msg is None:
			log.info('{} OK'.format(log_prefix))
			messages.success(request, u'Забег «{}» из серии «{}» успешно удалён.'.format(event_name, series))
		else:
			log.error('{} {}'.format(log_prefix, error_msg), exc_info=log_exc_info)
			messages.warning(
				request, u'Не удалось удалить забег «{}» из серии «{}»<br />({}).'.format(
					event_name, series, error_msg
				)
			)
		return redirect(event.series)

	return event_details(request, event_id=event_id, event=event, frmForEvent=form)
예제 #8
0
def event_change_series(request, event_id):
	event = get_object_or_404(models.Event, pk=event_id)
	context, has_rights, target = check_rights(request, event=event)
	if not has_rights:
		return target
	ok_to_move = False
	if 'frmForSeries_submit' in request.POST:
		form = forms.ForSeriesForm(request.POST, auto_id='frmForSeries_%s')
		if form.is_valid():
			new_series_id = models.int_safe(request.POST.get('new_series_id', 0))
			if new_series_id:
				if new_series_id != event.series.id:
					new_series = models.Series.objects.filter(pk=new_series_id).first()
					if new_series:
						ok_to_move = True
					else:
						messages.warning(request, u'Серия, в которую нужно переместить забег, не найдена.')
				else:
					messages.warning(request, u'Забег уже находится в этой серии.')
			else:
				messages.warning(request, u'Серия, на которую нужно заменить текущую, не указана.')
		else:
			messages.warning(request, u"Серия не заменена. Пожалуйста, исправьте ошибки в форме.")
	else:
		form = None
		messages.warning(request, u"Вы не указали новую серию.")
	if ok_to_move:
		old_series = event.series
		log = logging.getLogger('structure_modification')
		log_prefix = 'event_change_series: event {}, series {}->{}, by user {}.'.format(event_id, old_series.id, new_series.id, request.user.id)
		log.debug('{} before flock'.format(log_prefix))
		log_exc_info = False
		with Flock_mutex(LOCK_FILE_FOR_RATED_TREE_MODIFICATIONS):
			log.debug('{} trnsctn start'.format(log_prefix))
			try:
				with transaction.atomic():
					change_parent(event, new_series)  # to adapt the starrating data
					event.series = new_series
					event.save()
					for race in event.race_set.all():
						race.clean()
						race.save()
					log_change_event_series(request.user, event)
					update_course_records(old_series)
					update_course_records(event.series)
				log.debug('{} trnsctn end'.format(log_prefix))
			except (UpdatedRecordExistsError, AssertionError) as e:
				error_msg = repr(e)
				if isinstance(e, AssertionError):
					log_exc_info = True
			else:
				error_msg = None
		if error_msg is None:
			log.info('{} OK'.format(log_prefix))
			messages.success(request, u'Забег «{}» успешно перемещён из серии «{}» в серию «{}».'.format(event, old_series, event.series))
		else:
			log.error('{} {}'.format(log_prefix, error_msg), exc_info=log_exc_info)
			messages.warning(request, u'Не удалось переместить забег «{}» из серии «{}» в серию «{}»<br />({}).'.format(event, old_series, event.series, error_msg))

		return redirect(event.get_editor_url())

	return event_details(request, event_id=event_id, event=event, frmForSeries=form)