Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make passing ids to GradesService optional, create GradeInput,SubjectInput classes #1621

Merged
merged 8 commits into from
May 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
144 changes: 112 additions & 32 deletions app/lib/grades/grades_service/grades_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -124,13 +124,15 @@ class GradesService {
);
}

void addTerm({
required TermId id,
TermId addTerm({
required String name,
required GradeTypeId finalGradeType,
required GradingSystem gradingSystem,
required bool isActiveTerm,
@visibleForTesting TermId? id,
}) {
final termId = id ?? TermId(Id.generate().value);

IList<TermModel> newTerms = _terms;
if (isActiveTerm) {
newTerms = newTerms.map((term) => term.setIsActiveTerm(false)).toIList();
Expand All @@ -142,14 +144,15 @@ class GradesService {

newTerms = newTerms.add(
TermModel(
id: id,
id: termId,
isActiveTerm: isActiveTerm,
name: name,
finalGradeType: finalGradeType,
gradingSystem: gradingSystem.toGradingSystemModel(),
),
);
_updateTerms(newTerms);
return termId;
}

/// Edits the given values of the term (does not edit if the value is null).
Expand Down Expand Up @@ -270,48 +273,56 @@ class GradesService {
_updateTerm(newTerm);
}

void addGrade({
GradeId addGrade({
required SubjectId subjectId,
required TermId termId,
required Grade value,
required GradeInput value,
@visibleForTesting GradeId? id,
}) {
final gradeId = id ?? GradeId(Id.generate().value);
final grade = value.toGrade(gradeId);

final subject = _getSubjectOrThrow(subjectId);
if (!_hasGradeTypeWithId(value.type)) {
throw GradeTypeNotFoundException(value.type);
}

if (_hasGradeWithId(value.id)) {
throw DuplicateGradeIdException(value.id);
if (_hasGradeWithId(gradeId)) {
throw DuplicateGradeIdException(gradeId);
}

var newTerm = _term(termId);
if (!newTerm.hasSubject(subjectId)) {
newTerm = newTerm.addSubject(subject);
}
newTerm = newTerm.addGrade(value, toSubject: subjectId);
newTerm = newTerm.addGrade(grade, toSubject: subjectId);
_updateTerm(newTerm);

return gradeId;
}

/// Replaces an existing grade with [Grade.id] with the [newGrade].
/// Replaces an existing grade with [id] with the [newGrade].
///
/// Throws [GradeNotFoundException] if no grade with the given [Grade.id]
/// of [newGrade] exists.
/// Throws [GradeNotFoundException] if no grade with the given [id] of
/// [newGrade] exists.
///
/// Throws [GradeTypeNotFoundException] if the grade type of [newGrade] does
/// not exist.
///
/// Throws [InvalidGradeValueException] if the [Grade.value] of the [newGrade]
/// is not valid for the [Grade.gradingSystem] of the [newGrade].
void editGrade(Grade newGrade) {
if (!_hasGradeWithId(newGrade.id)) {
throw GradeNotFoundException(newGrade.id);
/// Throws [InvalidGradeValueException] if the [_Grade.value] of the
/// [newGrade] is not valid for the [_Grade.gradingSystem] of the [newGrade].
void editGrade(GradeId id, GradeInput newGrade) {
final grade = newGrade.toGrade(id);

if (!_hasGradeWithId(id)) {
throw GradeNotFoundException(id);
}
if (!_hasGradeTypeWithId(newGrade.type)) {
throw GradeTypeNotFoundException(newGrade.type);
}

final term = _terms.firstWhere((term) => term.containsGrade(newGrade.id));
final newTerm = term.replaceGrade(newGrade);
final term = _terms.firstWhere((term) => term.containsGrade(id));
final newTerm = term.replaceGrade(grade);

_updateTerm(newTerm);
}
Expand Down Expand Up @@ -396,14 +407,23 @@ class GradesService {
/// Creates a custom grade type.
///
/// If the grade type already exists, nothing will happen.
void addCustomGradeType(GradeType gradeType) {
if (_hasGradeTypeWithId(gradeType.id)) {
// Already exists
return;
GradeTypeId addCustomGradeType({
required String displayName,
@visibleForTesting GradeTypeId? id,
}) {
final gradeTypeId = id ?? GradeTypeId(Id.generate().value);
final gradeType = GradeType(id: gradeTypeId, displayName: displayName);

if (_hasGradeTypeWithId(gradeTypeId)) {
// Already exists.
return gradeTypeId;
}

final newState =
_state.copyWith(customGradeTypes: _customGradeTypes.add(gradeType));
_updateState(newState);

return gradeTypeId;
}

/// Edits properties of a custom grade type.
Expand Down Expand Up @@ -488,16 +508,22 @@ class GradesService {
return getPossibleGradeTypes().firstWhere((gt) => gt.id == finalGradeType);
}

void addSubject(Subject subject) {
SubjectId addSubject(SubjectInput subjectInput,
{@visibleForTesting SubjectId? id}) {
final subjectId = id ?? SubjectId(Id.generate().value);
final subject = subjectInput.toSubject(subjectId);

if (subject.createdOn != null) {
throw ArgumentError(
'The createdOn field should not be set when adding a new subject.');
}
if (getSubjects().any((s) => s.id == subject.id)) {
throw SubjectAlreadyExistsException(subject.id);
if (getSubjects().any((s) => s.id == subjectId)) {
throw SubjectAlreadyExistsException(subjectId);
}
final newState = _state.copyWith(subjects: _subjects.add(subject));
_updateState(newState);

return subjectId;
}

IList<Subject> getSubjects() {
Expand Down Expand Up @@ -867,9 +893,21 @@ class GradeValue extends Equatable {
});
}

class Grade {
class _Grade extends GradeInput {
final GradeId id;
_Grade({
required this.id,
required super.value,
required super.gradingSystem,
required super.type,
required super.date,
required super.takeIntoAccount,
required super.title,
required super.details,
});
}

class GradeInput {
/// Either a number or a string like '1+', '2-', etc.
final Object value;
final GradingSystem gradingSystem;
Expand All @@ -884,8 +922,7 @@ class Grade {
/// Punkte'.
final String? details;

Grade({
required this.id,
GradeInput({
required this.value,
required this.gradingSystem,
required this.type,
Expand All @@ -896,6 +933,21 @@ class Grade {
});
}

extension on GradeInput {
_Grade toGrade(GradeId id) {
return _Grade(
id: id,
value: value,
gradingSystem: gradingSystem,
type: type,
date: date,
takeIntoAccount: takeIntoAccount,
title: title,
details: details,
);
}
}

enum WeightType {
perGrade,
perGradeType,
Expand All @@ -906,8 +958,24 @@ class GradeTypeId extends Id {
const GradeTypeId(super.value);
}

class Subject extends Equatable {
class Subject extends SubjectInput {
final SubjectId id;

@override
List<Object?> get props =>
[id, design, name, abbreviation, connectedCourses, createdOn];

const Subject({
required this.id,
required super.design,
required super.name,
required super.abbreviation,
required super.connectedCourses,
super.createdOn,
});
}

class SubjectInput extends Equatable {
final Design design;
final String name;
final String abbreviation;
Expand All @@ -916,10 +984,9 @@ class Subject extends Equatable {

@override
List<Object?> get props =>
[id, design, name, abbreviation, connectedCourses, createdOn];
[design, name, abbreviation, connectedCourses, createdOn];

const Subject({
required this.id,
const SubjectInput({
required this.design,
required this.name,
required this.abbreviation,
Expand All @@ -928,6 +995,19 @@ class Subject extends Equatable {
});
}

extension on SubjectInput {
Subject toSubject(SubjectId id) {
return Subject(
id: id,
design: design,
name: name,
abbreviation: abbreviation,
connectedCourses: connectedCourses,
createdOn: createdOn,
);
}
}

class ConnectedCourse extends Equatable {
final CourseId id;
final String name;
Expand Down
8 changes: 5 additions & 3 deletions app/lib/grades/grades_service/src/term.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
//
// SPDX-License-Identifier: EUPL-1.2

// ignore_for_file: library_private_types_in_public_api

part of '../grades_service.dart';

@visibleForTesting
Expand Down Expand Up @@ -174,7 +176,7 @@ class TermModel extends Equatable {
return _copyWith(finalGradeType: gradeType, subjects: newSubjects);
}

TermModel addGrade(Grade grade, {required SubjectId toSubject}) {
TermModel addGrade(_Grade grade, {required SubjectId toSubject}) {
var subject = subjects.firstWhere(
(s) => s.id == toSubject,
orElse: () => throw SubjectNotFoundException(toSubject),
Expand All @@ -189,7 +191,7 @@ class TermModel extends Equatable {
: _copyWith(subjects: subjects.add(subject));
}

TermModel replaceGrade(Grade grade) {
TermModel replaceGrade(_Grade grade) {
final subject = subjects.firstWhere((s) => s.hasGrade(grade.id));
final gradeModel = _toGradeModel(grade, subjectId: subject.id);

Expand All @@ -213,7 +215,7 @@ class TermModel extends Equatable {
);
}

GradeModel _toGradeModel(Grade grade, {required SubjectId subjectId}) {
GradeModel _toGradeModel(_Grade grade, {required SubjectId subjectId}) {
final originalInput = grade.value;
final gradingSystem = grade.gradingSystem.toGradingSystemModel();
final gradeVal = gradingSystem.toNumOrThrow(grade.value);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
//
// SPDX-License-Identifier: EUPL-1.2

import 'package:common_domain_models/common_domain_models.dart';
import 'package:crash_analytics/crash_analytics.dart';
import 'package:flutter/material.dart';
import 'package:sharezone/grades/grades_service/grades_service.dart';
Expand Down Expand Up @@ -57,9 +56,7 @@ class CreateTermPageController extends ChangeNotifier {
}

try {
final termId = TermId(Id.generate().value);
gradesService.addTerm(
id: termId,
final termId = gradesService.addTerm(
name: view.name!,
isActiveTerm: view.isActiveTerm,
finalGradeType: GradeType.schoolReportGrade.id,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import 'package:fast_immutable_collections/fast_immutable_collections.dart';
import 'package:flutter/material.dart';
import 'package:group_domain_models/group_domain_models.dart';
import 'package:sharezone/grades/grades_service/grades_service.dart';
import 'package:sharezone_utils/random_string.dart';

import 'grades_dialog_view.dart';

Expand Down Expand Up @@ -448,12 +447,10 @@ class GradesDialogController extends ChangeNotifier {
};

try {
final gradeId = GradeId(randomIDString(20));
gradesService.addGrade(
subjectId: _selectSubjectId!,
termId: _selectedTermId!,
value: Grade(
id: gradeId,
value: GradeInput(
type: _gradeType.id,
value: _grade!,
date: _date,
Expand Down Expand Up @@ -489,10 +486,13 @@ class GradesDialogController extends ChangeNotifier {
final connectedCourses = _getConnectedCourses(subject.id);

gradesService.addSubject(
Subject(
// Not passing the id here would require some refactoring, so for now we
// just pass the id of the subject.
// ignore: invalid_use_of_visible_for_testing_member
id: subject.id,
SubjectInput(
abbreviation: subject.abbreviation,
design: subject.design,
id: subject.id,
name: subject.name,
connectedCourses: connectedCourses,
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ class TermDialogController extends ChangeNotifier {

Future<void> addTerm() async {
gradesService.addTerm(
id: TermId(termName),
gradingSystem: gradingSystem,
name: termName,
finalGradeType: GradeType.schoolReportGrade.id,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,12 +185,9 @@ class TermSettingsPageController extends ChangeNotifier {
SubjectId _createSubject(SubjectId subjectId) {
final subject = view.subjects.firstWhere((s) => s.id == subjectId);
final connectedCourses = _getConnectedCourses(subjectId);
// We generate a new subject ID because the previous subject ID was just the
// course ID (as temporary ID).
final newSubjectId = SubjectId(Id.generate().value);
gradesService.addSubject(
Subject(
id: newSubjectId,

final newSubjectId = gradesService.addSubject(
SubjectInput(
design: subject.design,
name: subject.displayName,
abbreviation: subject.abbreviation,
Expand Down
Loading
Loading