Example #1
0
def login_remote_client(request):
    """Login for the JuliaBase Remote Client.  It expects ``username`` and
    ``password``.  AJAX code shouldn't need it because it has the cookie
    already.  An HTTP GET request yields nothing – this can be used to get the
    CSRF cookie.

    :param request: the current HTTP Request object

    :type request: HttpRequest

    :return:
      the HTTP response object.  It is a JSON boolean object, whether the login
      was successful or not.

    :rtype: HttpResponse
    """
    if request.method == "POST":
        try:
            username = request.POST["username"]
            password = request.POST["password"]
        except KeyError:
            raise JSONRequestException(3,
                                       '"username" and/or "password" missing')
        user = django.contrib.auth.authenticate(username=username,
                                                password=password)
        if user is not None and user.is_active:
            django.contrib.auth.login(request, user)
            return respond_in_json(True)
        raise JSONRequestException(4, "user could not be authenticated")
    else:
        return respond_in_json(None)
Example #2
0
def set_start_kicker_number(request, username):
    if request.user.username != "kicker":
        raise JSONRequestException(
            3005, "You must be the user \"kicker\" to use this function.")
    try:
        start_kicker_number = int(request.POST["start_kicker_number"])
        timestamp = django.utils.timezone.make_aware(
            datetime.datetime.strptime(request.POST["timestamp"],
                                       "%Y-%m-%d %H:%M:%S"))
    except KeyError:
        raise JSONRequestException(3, error.args[0])
    except ValueError as error:
        raise JSONRequestException(5, error.args[0])
    player, created = django.contrib.auth.models.User.objects.get_or_create(
        username=username)
    if created:
        player.set_unusable_password()
        player.save()
    if models.KickerNumber.objects.filter(player=player).exists():
        raise JSONRequestException(
            3006, "There are already kicker numbers stored for this user.")
    models.KickerNumber.objects.create(player=player,
                                       number=start_kicker_number,
                                       timestamp=timestamp)
    return respond_in_json(True)
Example #3
0
def cancel_match(request, id_):
    match = get_object_or_404(models.Match,
                              pk=int_or_zero(id_)) if id_ else None
    if match and match.reporter != request.user:
        raise JSONRequestException(
            3005, "You must be the original reporter of this match.")
    if match.finished:
        raise JSONRequestException(3003, "A finished match can't be canceled.")
    match.delete()
    return respond_in_json(True)
Example #4
0
def get_folded_processes(request, sample_id):
    """Get all the IDs from the processes, who have to be folded.

    :param request: The current HTTP Request object.  It must contain all the process
        IDs of the processes from the selected sample.
    :param sample_id: The sample ID represent the data sheet the user wants to see.

    :type request: HttpRequest
    :type sample_id: unicode

    :return:
     The process IDs of the processes, who have to be folded on the samples data sheet.

    :rtype: HttpResponse
    """
    try:
        process_ids = [
            utils.convert_id_to_int(id_)
            for id_ in request.GET["process_ids"].split(",")
        ]
    except KeyError:
        raise JSONRequestException(3, '"process_ids" missing')
    utils.convert_id_to_int(sample_id)
    folded_process_classes = ContentType.objects.filter(
        dont_show_to_user=request.user.samples_user_details)
    exceptional_processes_by_sample_id = json.loads(
        request.user.samples_user_details.folded_processes).get(sample_id, [])
    folded_process_ids = []
    for process_id in process_ids:
        if _is_folded(process_id,
                      folded_process_classes,
                      exceptional_processes_by_sample_id,
                      switch=False):
            folded_process_ids.append(process_id)
    return respond_in_json(folded_process_ids)
Example #5
0
def change_my_samples(request):
    """Adds or remove samples from “My Samples”.

    :param request: The current HTTP Request object.  It must contain the sample
        IDs of the to-be-removed samples comma-separated list in ``"remove"``
        and the to-be-added sample IDs in ``"add"``.  Both can be empty.
        Moreover, it may contain the ID of the user whose “My Samples” should
        be changed in ``"user"``.  If not given, the logged-in user is used.
        If given, the currently logged-in user must be admin.

    :type request: HttpRequest

    :return:
      The IDs of the samples for which the change had to be actually made.  It
      returns a 404 if one sample wasn't found.

    :rtype: HttpResponse
    """
    try:
        sample_ids_to_remove = {
            int(id_)
            for id_ in request.POST.get("remove", "").split(",") if id_
        }
        sample_ids_to_add = {
            int(id_)
            for id_ in request.POST.get("add", "").split(",") if id_
        }
    except ValueError:
        raise Http404("One or more of the sample IDs were invalid.")
    user = request.user
    user_id = request.POST.get("user")
    if user_id:
        if not request.user.is_superuser:
            raise JSONRequestException(
                6, "Only admins can change other users' My Samples.")
        try:
            user = django.contrib.auth.models.User.objects.get(pk=user_id)
        except django.contrib.auth.models.User.DoesNotExist:
            raise Http404("User not found.")
    doubled_ids = sample_ids_to_remove & sample_ids_to_add
    sample_ids_to_remove -= doubled_ids
    sample_ids_to_add -= doubled_ids
    try:
        samples_to_remove = models.Sample.objects.in_bulk(
            list(sample_ids_to_remove))
        samples_to_add = utils.restricted_samples_query(request.user).in_bulk(
            list(sample_ids_to_add))
    except models.Sample.DoesNotExist:
        raise Http404("One or more of the sample IDs could not be found.")
    current_my_samples = set(user.my_samples.values_list("id", flat=True))
    changed_sample_ids = sample_ids_to_remove & current_my_samples | \
        sample_ids_to_add - (current_my_samples - sample_ids_to_remove)
    user.my_samples.remove(*samples_to_remove.values())
    user.my_samples.add(*samples_to_add.values())
    return respond_in_json(changed_sample_ids)
Example #6
0
def get_matching_solarsimulator_measurement(request, sample_id, irradiation,
                                            cell_position, date):
    """Finds the solarsimulator measurement which is best suited for the given
    data file.  This view is to solve the problem that for non-standard-Jülich
    cell layouts, many single data files must be merged into one solarsimulator
    measurements.  When importing them one by one, one has to find the already
    existing measurement to which they must be added.  This is done by this
    view.

    It returns the ID of the measurement, or ``None`` if none was found.

    :param request: the HTTP request object
    :param sample_id: the ID of the sample which was measured
    :param irradiation: the irradiation (AM1.5, BG7 etc) which was used
    :param cell_position: the position of the cell on the layout; don't mix it
        up with the *index* of the cell, which is the number used in the
        Solarsimulator datafile in the first column
    :param date: the day (not the time) of the measurement in YYYY-MM-DD format

    :type request: HttpRequest
    :type sample_id: unicode
    :type irradiation: unicode
    :type cell_position: unicode
    :type date: unicode

    :return:
      the HTTP response object

    :rtype: HttpResponse
    """
    try:
        filepath = request.GET["filepath"]
    except KeyError:
        raise JSONRequestException(3, '"filepath" missing')
    try:
        return respond_in_json(
            _get_solarsimulator_measurement_by_filepath(
                filepath, request.user))
    except Http404:
        sample = get_object_or_404(models.Sample, id=sample_id)
        start_date = django.utils.timezone.make_aware(
            datetime.datetime.strptime(date, "%Y-%m-%d"))
        end_date = start_date + datetime.timedelta(days=1)
        matching_measurements = institute.models.SolarsimulatorMeasurement.objects.filter(
            samples__id=sample_id, irradiation=irradiation, timestamp__gte=start_date, timestamp__lt=end_date). \
            exclude(cells__position=cell_position).order_by("timestamp")
        if matching_measurements.exists():
            solarsimulator_measurement = matching_measurements[0]
            permissions.assert_can_fully_view_sample(request.user, sample)
            permissions.assert_can_view_physical_process(
                request.user, solarsimulator_measurement)
            return respond_in_json(solarsimulator_measurement.id)
        else:
            return respond_in_json(None)
Example #7
0
def get_solarsimulator_measurement_by_filepath(request):
    """Returns the measurement ID of the solarsimulator measurement which
    contains the given filepath.  See `_get_solarsimulator_measurement_by_filepath`.  The filepath
    is given in the query string parameter “``filepath``”.

    :param request: the HTTP request object

    :type request: HttpRequest

    :return:
      the HTTP response object

    :rtype: HttpResponse
    """
    try:
        filepath = request.GET["filepath"]
    except KeyError:
        raise JSONRequestException(3, '"filepath" missing')
    return respond_in_json(_get_solarsimulator_measurement_by_filepath(filepath, request.user))
Example #8
0
def get_current_structuring(request, sample_id):
    """Find the structuring process which is active for the given sample at a
    given timestamp.  The “``timestamp``” is an optional parameter in the query
    string in the format ``YYYY-MM-YY HH:MM:SS``.  If given, find the latest
    structuring process before that timestamp.  Otherwise, find the lastest
    structuring of the sample.  Typically, the timestamp is the timestamp of
    the process which needs the structuring, e.g. a solarsimulator measurement.

    It returns the ID of the structuring process, or ``None`` if none was
    found.

    :param request: the HTTP request object
    :param sample_id: the ID of the sample

    :type request: HttpRequest
    :type sample_id: unicode

    :return:
      the HTTP response object

    :rtype: HttpResponse
    """
    sample = get_object_or_404(models.Sample, id=sample_id)
    try:
        timestamp = django.utils.timezone.make_aware(
            datetime.datetime.strptime(
                request.GET["timestamp"].partition(".")[0],
                "%Y-%m-%d %H:%M:%S"))
    except KeyError:
        timestamp = None
    except ValueError:
        raise JSONRequestException(5, '"timestamp" has invalid format')
    try:
        structuring = layouts.get_current_structuring(sample, timestamp)
    except layouts.NoStructuringFound:
        result = None
    else:
        permissions.assert_can_fully_view_sample(request.user, sample)
        permissions.assert_can_view_physical_process(request.user, structuring)
        result = structuring.id
    return respond_in_json(result)
Example #9
0
def add_sample(request):
    """Adds a new sample to the database.  It is added without processes.  This
    view can only be used by admin accounts.

    :param request: the current HTTP Request object; it must contain the sample
        data in the POST data.

    :return:
      The primary key of the created sample.  ``False`` if something went
      wrong.  It may return a 404 if the topic or the currently responsible
      person wasn't found.

    :rtype: HttpResponse
    """
    try:
        name = request.POST["name"]
        current_location = request.POST["current_location"]
        currently_responsible_person = request.POST[
            "currently_responsible_person"]
        purpose = request.POST.get("purpose", "")
        tags = request.POST.get("tags", "")
        topic = request.POST.get("topic")
    except KeyError as error:
        raise JSONRequestException(
            3, "'{}' parameter missing.".format(error.args[0]))
    if len(name) > 30:
        raise JSONRequestException(5, "The sample name is too long.")
    name_format = utils.sample_name_format(name)
    if name_format is None or \
       not request.user.is_staff and name_format not in settings.SAMPLE_NAME_FORMATS["provisional"].get("possible_renames", set()):
        raise JSONRequestException(5, "The sample name is invalid.")
    eligible_users = django.contrib.auth.models.User.objects.filter(
        is_active=True, jb_user_details__department__isnull=False)
    try:
        currently_responsible_person = eligible_users.get(
            pk=utils.convert_id_to_int(currently_responsible_person))
    except django.contrib.auth.models.User.DoesNotExist:
        raise Http404("Currently reponsible user not found.")
    if topic:
        all_topics = Topic.objects.all() if request.user.is_staff else \
                     Topic.objects.filter(Q(confidential=False) | Q(members=request.user))
        try:
            topic = all_topics.get(pk=utils.convert_id_to_int(topic))
        except Topic.DoesNotExist:
            raise Http404("Topic not found")
    try:
        sample = models.Sample.objects.create(
            name=name,
            current_location=current_location,
            currently_responsible_person=currently_responsible_person,
            purpose=purpose,
            tags=tags,
            topic=topic)
        # They will be shadowed anyway.  Nevertheless, this action is an
        # emergency measure.  Probably the samples the aliases point to should
        # be merged with the sample but this can't be decided automatically.
        models.SampleAlias.objects.filter(name=name).delete()
    except IntegrityError as error:
        error_message = "The sample with this data could not be added."
        if request.user.is_staff:
            error_message += " {}".format(error)
        raise JSONRequestException(5, error_message)
    sample.watchers.add(request.user)
    return respond_in_json(sample.pk)
Example #10
0
def edit_match(request, id_=None):
    match = get_object_or_404(models.Match,
                              pk=int_or_zero(id_)) if id_ else None
    if match and match.reporter != request.user:
        raise JSONRequestException(
            3005, "You must be the original reporter of this match.")
    try:
        if not match:
            player_a_1 = get_object_or_404(django.contrib.auth.models.User,
                                           username=request.POST["player_a_1"])
            player_a_2 = get_object_or_404(django.contrib.auth.models.User,
                                           username=request.POST["player_a_2"])
            player_b_1 = get_object_or_404(django.contrib.auth.models.User,
                                           username=request.POST["player_b_1"])
            player_b_2 = get_object_or_404(django.contrib.auth.models.User,
                                           username=request.POST["player_b_2"])
        goals_a = int(request.POST["goals_a"])
        goals_b = int(request.POST["goals_b"])
        seconds = float(request.POST["seconds"])
        finished = request.POST.get("finished") == "on"
        timestamp = datetime.datetime.strptime(request.POST["timestamp"],
                                               "%Y-%m-%d %H:%M:%S")
    except KeyError as error:
        raise JSONRequestException(3, error.args[0])
    except ValueError as error:
        raise JSONRequestException(5, error.args[0])
    if not match:
        if player_a_1 == player_a_2 and player_b_1 != player_b_2 or player_a_1 != player_a_2 and player_b_1 == player_b_2:
            raise JSONRequestException(
                3000, "Games with three players can't be processed.")
        if player_a_1 == player_a_2 == player_b_1 == player_b_2:
            raise JSONRequestException(3001,
                                       "All players are the same person.")
        unfinished_matches = models.Match.objects.filter(finished=False)
        if unfinished_matches.exists():
            if unfinished_matches.exclude(reporter=request.user).exists():
                raise JSONRequestException(
                    3004,
                    "You can't add a match if another one of another reporter is not yet finished."
                )
            for match in unfinished_matches.all():
                match.delete()
    else:
        if match.finished:
            raise JSONRequestException(
                3003, "A finished match can't be edited anymore.")
        player_a_1 = match.player_a_1
        player_a_2 = match.player_a_2
        player_b_1 = match.player_b_1
        player_b_2 = match.player_b_2
    try:
        seconds_since_most_recent = (
            timestamp - models.Match.objects.latest("timestamp").timestamp
        ).total_seconds()
        if seconds_since_most_recent <= 0:
            if seconds_since_most_recent < -10:
                raise JSONRequestException(
                    3002, "This game is not the most recent one.")
            else:
                timestamp = models.Match.objects.latest(
                    "timestamp").timestamp + datetime.timedelta(seconds=1)
    except models.Match.DoesNotExist:
        pass
    if match:
        match.player_a_1 = player_a_1
        match.player_a_2 = player_a_2
        match.player_b_1 = player_b_1
        match.player_b_2 = player_b_2
        match.goals_a = goals_a
        match.goals_b = goals_b
        match.timestamp = timestamp
        match.finished = finished
        match.seconds = seconds
        match.save()
    else:
        match = models.Match.objects.create(player_a_1=player_a_1,
                                            player_a_2=player_a_2,
                                            player_b_1=player_b_1,
                                            player_b_2=player_b_2,
                                            goals_a=goals_a,
                                            goals_b=goals_b,
                                            timestamp=timestamp,
                                            finished=finished,
                                            seconds=seconds,
                                            reporter=request.user)
    if match.finished:
        if seconds <= 0:
            raise JSONRequestException(5, "Seconds must be positive.")
        match_result = MatchResult(match)
        match_result.add_kicker_numbers()
        match_result.add_stock_values()
    else:
        match.seconds = max(1, match.seconds)
        match_result = MatchResult(match)
    return respond_in_json((match.pk, match_result.expected_goal_difference,
                            match_result.estimated_win_team_1))
Example #11
0
def edit_match(request, id_=None):
    match = get_object_or_404(models.Match,
                              pk=int_or_zero(id_)) if id_ else None
    if match and match.reporter != request.user:
        raise JSONRequestException(
            3005, _("You must be the original reporter of this match."))
    try:
        if not match:
            player_a_1 = get_object_or_404(django.contrib.auth.models.User,
                                           username=request.POST["player_a_1"])
            player_a_2 = get_object_or_404(django.contrib.auth.models.User,
                                           username=request.POST["player_a_2"])
            player_b_1 = get_object_or_404(django.contrib.auth.models.User,
                                           username=request.POST["player_b_1"])
            player_b_2 = get_object_or_404(django.contrib.auth.models.User,
                                           username=request.POST["player_b_2"])
        goals_a = int(request.POST["goals_a"])
        goals_b = int(request.POST["goals_b"])
        seconds = float(request.POST["seconds"])
        finished = request.POST.get("finished") == "on"
        timestamp = django.utils.timezone.make_aware(
            datetime.datetime.strptime(request.POST["timestamp"],
                                       "%Y-%m-%d %H:%M:%S"))
    except KeyError as error:
        raise JSONRequestException(3, error.args[0])
    except ValueError as error:
        raise JSONRequestException(5, error.args[0])
    if not match:
        if player_a_1 == player_a_2 and player_b_1 != player_b_2 or player_a_1 != player_a_2 and player_b_1 == player_b_2:
            raise JSONRequestException(
                3000, _("Matches with three players can't be processed."))
        if player_a_1 == player_a_2 == player_b_1 == player_b_2:
            raise JSONRequestException(3001,
                                       _("All players are the same person."))
        models.Match.objects.filter(finished=False,
                                    reporter=request.user).delete()
    else:
        if match.finished:
            raise JSONRequestException(
                3003, _("A finished match can't be edited anymore."))
        player_a_1 = match.player_a_1
        player_a_2 = match.player_a_2
        player_b_1 = match.player_b_1
        player_b_2 = match.player_b_2
    try:
        if finished and models.KickerNumber.objects.latest(
        ).timestamp > timestamp:
            raise JSONRequestException(
                3002,
                _("This match is older than the most recent kicker numbers."))
    except models.KickerNumber.DoesNotExist:
        pass
    if match:
        match.player_a_1 = player_a_1
        match.player_a_2 = player_a_2
        match.player_b_1 = player_b_1
        match.player_b_2 = player_b_2
        match.goals_a = goals_a
        match.goals_b = goals_b
        match.timestamp = timestamp
        match.finished = finished
        match.seconds = seconds
        match.save()
    else:
        match = models.Match.objects.create(player_a_1=player_a_1,
                                            player_a_2=player_a_2,
                                            player_b_1=player_b_1,
                                            player_b_2=player_b_2,
                                            goals_a=goals_a,
                                            goals_b=goals_b,
                                            timestamp=timestamp,
                                            finished=finished,
                                            seconds=seconds,
                                            reporter=request.user)
    if match.finished:
        if seconds <= 0:
            raise JSONRequestException(5, _("Seconds must be positive."))
        match_result = MatchResult(match)
        match_result.add_kicker_numbers()
        match_result.add_stock_values()
    else:
        match.seconds = max(1, match.seconds)
        match_result = MatchResult(match)
    return respond_in_json((match.pk, match_result.expected_goal_difference,
                            match_result.estimated_win_team_1))