Skip to content

Commit 0d84208

Browse files
committed
General: Unmap the vacated jhi_user columns and make the comments evergreen
The twelve extracted columns were still mapped on User and marked @deprecated(forRemoval = true) so that a rollback could fall back to them. No rollback is planned - the change is verified on a production clone and against a production dump - and keeping them mapped deferred the point of the extraction: Hibernate selects every mapped column, so the user row stayed as wide to read as before. Unmapping them here realises the narrower read now instead of in the follow-up. The columns themselves stay in the database until the follow-up, so a node running the previous version keeps working through a rolling deployment. Both NOT NULL columns among them carry a database default, so an insert that omits them is still valid. Also fold the activity-row creation into one helper, reached by all three timestamps rather than shared by two and inlined by the third, and rewrite the comments that narrated the move instead of describing the code.
1 parent 789e03c commit 0d84208

23 files changed

Lines changed: 281 additions & 352 deletions

src/main/java/de/tum/cit/aet/artemis/account/domain/User.java

Lines changed: 2 additions & 258 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33
import static de.tum.cit.aet.artemis.core.config.Constants.USERNAME_MAX_LENGTH;
44
import static de.tum.cit.aet.artemis.core.config.Constants.USERNAME_MIN_LENGTH;
55

6-
import java.time.Instant;
7-
import java.time.ZonedDateTime;
86
import java.util.Collections;
97
import java.util.EnumSet;
108
import java.util.HashMap;
@@ -17,8 +15,6 @@
1715
import jakarta.persistence.CascadeType;
1816
import jakarta.persistence.Column;
1917
import jakarta.persistence.Entity;
20-
import jakarta.persistence.EnumType;
21-
import jakarta.persistence.Enumerated;
2218
import jakarta.persistence.FetchType;
2319
import jakarta.persistence.JoinColumn;
2420
import jakarta.persistence.JoinTable;
@@ -35,7 +31,6 @@
3531
import org.hibernate.Hibernate;
3632
import org.hibernate.annotations.BatchSize;
3733
import org.jspecify.annotations.NonNull;
38-
import org.jspecify.annotations.Nullable;
3934
import org.springframework.security.core.authority.SimpleGrantedAuthority;
4035
import org.springframework.security.web.webauthn.api.Bytes;
4136

@@ -50,7 +45,6 @@
5045
import de.tum.cit.aet.artemis.communication.domain.SavedPost;
5146
import de.tum.cit.aet.artemis.core.config.Constants;
5247
import de.tum.cit.aet.artemis.core.domain.AbstractAuditingEntity;
53-
import de.tum.cit.aet.artemis.core.domain.AiSelectionDecision;
5448
import de.tum.cit.aet.artemis.core.domain.CourseRole;
5549
import de.tum.cit.aet.artemis.core.domain.UserCourseRole;
5650
import de.tum.cit.aet.artemis.core.domain.converter.BytesConverter;
@@ -133,7 +127,7 @@ public class User extends AbstractAuditingEntity implements Participant {
133127
* </ol>
134128
* The presence of a recovery key consequently distinguishes (1) from (2), which is what made it possible to repair the
135129
* affected rows without touching accounts an admin had deactivated on purpose. The keys live in
136-
* {@code user_recovery_key}; {@link #activationKey} is the deprecated column they were read from before.
130+
* {@code user_recovery_key}.
137131
*/
138132
@NonNull
139133
@Column(nullable = false)
@@ -143,28 +137,6 @@ public class User extends AbstractAuditingEntity implements Participant {
143137
@Column(name = "is_deleted", nullable = false)
144138
private boolean deleted = false; // default value
145139

146-
/**
147-
* No longer read or written by anything; the activity timestamps live in {@code user_activity}.
148-
* <p>
149-
* Kept mapped for a rolling deployment; dropped together with the column by the follow-up.
150-
*
151-
* @deprecated superseded by {@code user_activity}
152-
*/
153-
@Deprecated(forRemoval = true)
154-
@Column(name = "last_login_date")
155-
private Instant lastLoginDate;
156-
157-
/**
158-
* No longer read or written by anything; the activity timestamps live in {@code user_activity}.
159-
* <p>
160-
* Kept mapped for a rolling deployment; dropped together with the column by the follow-up.
161-
*
162-
* @deprecated superseded by {@code user_activity}
163-
*/
164-
@Deprecated(forRemoval = true)
165-
@Column(name = "deletion_warning_sent_date")
166-
private Instant deletionWarningSentDate;
167-
168140
@Size(min = 2, max = 6)
169141
@Column(name = "lang_key", length = 6)
170142
private String langKey;
@@ -173,44 +145,6 @@ public class User extends AbstractAuditingEntity implements Participant {
173145
@Column(name = "image_url", length = 256)
174146
private String imageUrl;
175147

176-
/**
177-
* No longer read or written by anything; the recovery keys live in {@code user_recovery_key}, which documents the
178-
* invariant this key carries.
179-
* <p>
180-
* Kept mapped for a rolling deployment; dropped together with the column by the follow-up.
181-
*
182-
* @deprecated superseded by {@code user_recovery_key}
183-
*/
184-
@Deprecated(forRemoval = true)
185-
@Size(max = 20)
186-
@Column(name = "activation_key", length = 20)
187-
@JsonIgnore
188-
private String activationKey;
189-
190-
/**
191-
* No longer read or written by anything; the recovery keys live in {@code user_recovery_key}.
192-
* <p>
193-
* Kept mapped for a rolling deployment; dropped together with the column by the follow-up.
194-
*
195-
* @deprecated superseded by {@code user_recovery_key}
196-
*/
197-
@Deprecated(forRemoval = true)
198-
@Size(max = 20)
199-
@Column(name = "reset_key", length = 20)
200-
@JsonIgnore
201-
private String resetKey;
202-
203-
/**
204-
* No longer read or written by anything; the recovery keys live in {@code user_recovery_key}.
205-
* <p>
206-
* Kept mapped for a rolling deployment; dropped together with the column by the follow-up.
207-
*
208-
* @deprecated superseded by {@code user_recovery_key}
209-
*/
210-
@Deprecated(forRemoval = true)
211-
@Column(name = "reset_date")
212-
private Instant resetDate = null;
213-
214148
@Column(name = "is_internal", nullable = false)
215149
private boolean internal = true; // default value
216150

@@ -220,32 +154,6 @@ public class User extends AbstractAuditingEntity implements Participant {
220154
@Column(name = "is_test_user", nullable = false)
221155
private boolean isTestUser = false; // default value
222156

223-
/**
224-
* No longer read or written by anything. The personal VCS access token lives in {@code user_vcs_access_token}; use
225-
* {@code UserVcsAccessTokenService}.
226-
* <p>
227-
* Kept mapped so that nodes still running the previous version keep working through a rolling deployment. The field
228-
* and the column are dropped together by the follow-up that removes the column.
229-
*
230-
* @deprecated superseded by {@code user_vcs_access_token}
231-
*/
232-
@Deprecated(forRemoval = true)
233-
@Nullable
234-
@JsonIgnore
235-
@Column(name = "vcs_access_token")
236-
private String vcsAccessToken = null;
237-
238-
/**
239-
* The expiry date of the VCS access token, used to decide whether the token needs renewing.
240-
*
241-
* @deprecated superseded by {@code user_vcs_access_token}; see {@link #vcsAccessToken}
242-
*/
243-
@Deprecated(forRemoval = true)
244-
@Nullable
245-
@JsonIgnore
246-
@Column(name = "vcs_access_token_expiry_date")
247-
private ZonedDateTime vcsAccessTokenExpiryDate = null;
248-
249157
/**
250158
* When the account's credentials last changed - a completed password reset, a password change, or a deactivation.
251159
* A session issued before this point is not extended any further, so those events end long-lived sessions within one
@@ -255,36 +163,10 @@ public class User extends AbstractAuditingEntity implements Participant {
255163
* endpoints, so without {@code @JsonIgnore} this would tell every instructor and tutor when each of their course
256164
* members last changed their password.
257165
*/
258-
/**
259-
* No longer read or written by anything; the credential-change timestamp lives in {@code user_activity} with the
260-
* account's other lifecycle timestamps. It was read as part of every user load here, for the benefit of the one
261-
* caller that needs it.
262-
* <p>
263-
* Kept mapped for a rolling deployment; dropped together with the column by the follow-up.
264-
*
265-
* @deprecated superseded by {@code user_activity.credentials_changed_date}
266-
*/
267-
@Deprecated(forRemoval = true)
268-
@JsonIgnore
269-
@Column(name = "credentials_changed_date")
270-
private ZonedDateTime credentialsChangedDate = null;
271-
272166
@OneToMany(mappedBy = "user", fetch = FetchType.LAZY, cascade = CascadeType.REMOVE)
273167
@JsonIgnore
274168
private Set<UserCourseRole> courseRoles = new HashSet<>();
275169

276-
/**
277-
* No longer read or written by anything. The launch marker lives in {@code user_lti}; the lti module owns it.
278-
* <p>
279-
* Kept mapped so that nodes still running the previous version keep working through a rolling deployment. The field
280-
* and the column are dropped together by the follow-up that removes the column.
281-
*
282-
* @deprecated superseded by {@code user_lti}
283-
*/
284-
@Deprecated(forRemoval = true)
285-
@Column(name = "lti_created", nullable = false)
286-
private boolean ltiCreated = false; // default value
287-
288170
@OneToMany(mappedBy = "user", fetch = FetchType.LAZY, cascade = CascadeType.REMOVE, orphanRemoval = true)
289171
private final Set<SavedPost> savedPosts = new HashSet<>();
290172

@@ -324,43 +206,6 @@ public class User extends AbstractAuditingEntity implements Participant {
324206
@JsonIgnore
325207
private Set<PushNotificationDeviceConfiguration> pushNotificationDeviceConfigurations = new HashSet<>();
326208

327-
/**
328-
* No longer read or written by anything; the AI preferences live in {@code user_ai_preference}.
329-
* <p>
330-
* Kept mapped for a rolling deployment; dropped together with the column by the follow-up.
331-
*
332-
* @deprecated superseded by {@code user_ai_preference}
333-
*/
334-
@Nullable
335-
@Enumerated(EnumType.STRING)
336-
@Deprecated(forRemoval = true)
337-
@Column(name = "ai_selection_decision")
338-
private AiSelectionDecision aiSelectionDecision = null;
339-
340-
/**
341-
* No longer read or written by anything; the AI preferences live in {@code user_ai_preference}.
342-
* <p>
343-
* Kept mapped for a rolling deployment; dropped together with the column by the follow-up.
344-
*
345-
* @deprecated superseded by {@code user_ai_preference}
346-
*/
347-
@Nullable
348-
@Deprecated(forRemoval = true)
349-
@Column(name = "ai_selection_decision_date")
350-
private ZonedDateTime aiSelectionDecisionDate = null;
351-
352-
/**
353-
* No longer read or written by anything; the AI preferences live in {@code user_ai_preference}.
354-
* <p>
355-
* Kept mapped for a rolling deployment; dropped together with the column by the follow-up.
356-
*
357-
* @deprecated superseded by {@code user_ai_preference}
358-
*/
359-
@NonNull
360-
@Deprecated(forRemoval = true)
361-
@Column(name = "memiris_enabled", nullable = false)
362-
private boolean memirisEnabled = true;
363-
364209
@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
365210
@JsonIgnoreProperties(value = "user", allowSetters = true)
366211
@JoinColumn(name = "learner_profile_id")
@@ -463,30 +308,6 @@ public void setActivated(boolean activated) {
463308
this.activated = activated;
464309
}
465310

466-
public String getActivationKey() {
467-
return activationKey;
468-
}
469-
470-
public void setActivationKey(String activationKey) {
471-
this.activationKey = activationKey;
472-
}
473-
474-
public String getResetKey() {
475-
return resetKey;
476-
}
477-
478-
public void setResetKey(String resetKey) {
479-
this.resetKey = resetKey;
480-
}
481-
482-
public Instant getResetDate() {
483-
return resetDate;
484-
}
485-
486-
public void setResetDate(Instant resetDate) {
487-
this.resetDate = resetDate;
488-
}
489-
490311
public String getLangKey() {
491312
return langKey;
492313
}
@@ -574,14 +395,6 @@ public Map<Long, EnumSet<CourseRole>> getCourseRolesByCourseId() {
574395
return courseRolesByCourseIdTransient;
575396
}
576397

577-
public boolean isLtiCreated() {
578-
return ltiCreated;
579-
}
580-
581-
public void setLtiCreated(boolean ltiCreated) {
582-
this.ltiCreated = ltiCreated;
583-
}
584-
585398
public Set<Authority> getAuthorities() {
586399
return authorities;
587400
}
@@ -647,7 +460,7 @@ public List<SimpleGrantedAuthority> getGrantedAuthorities() {
647460
@Override
648461
public String toString() {
649462
return "User{" + "login='" + login + '\'' + ", firstName='" + firstName + '\'' + ", lastName='" + lastName + '\'' + ", email='" + email + '\'' + ", imageUrl='" + imageUrl
650-
+ '\'' + ", activated='" + activated + '\'' + ", langKey='" + langKey + '\'' + ", activationKey='" + activationKey + '\'' + "}";
463+
+ '\'' + ", activated='" + activated + '\'' + ", langKey='" + langKey + '\'' + "}";
651464
}
652465

653466
@JsonIgnore
@@ -684,51 +497,6 @@ public void setDeleted(boolean deleted) {
684497
this.deleted = deleted;
685498
}
686499

687-
@JsonIgnore
688-
public Instant getLastLoginDate() {
689-
return lastLoginDate;
690-
}
691-
692-
public void setLastLoginDate(Instant lastLoginDate) {
693-
this.lastLoginDate = lastLoginDate;
694-
}
695-
696-
@JsonIgnore
697-
public Instant getDeletionWarningSentDate() {
698-
return deletionWarningSentDate;
699-
}
700-
701-
public void setDeletionWarningSentDate(Instant deletionWarningSentDate) {
702-
this.deletionWarningSentDate = deletionWarningSentDate;
703-
}
704-
705-
@Nullable
706-
public String getVcsAccessToken() {
707-
return vcsAccessToken;
708-
}
709-
710-
@Nullable
711-
public ZonedDateTime getCredentialsChangedDate() {
712-
return credentialsChangedDate;
713-
}
714-
715-
public void setCredentialsChangedDate(@Nullable ZonedDateTime credentialsChangedDate) {
716-
this.credentialsChangedDate = credentialsChangedDate;
717-
}
718-
719-
public void setVcsAccessToken(@Nullable String vcsAccessToken) {
720-
this.vcsAccessToken = vcsAccessToken;
721-
}
722-
723-
@Nullable
724-
public ZonedDateTime getVcsAccessTokenExpiryDate() {
725-
return vcsAccessTokenExpiryDate;
726-
}
727-
728-
public void setVcsAccessTokenExpiryDate(@Nullable ZonedDateTime vcsAccessTokenExpiryDate) {
729-
this.vcsAccessTokenExpiryDate = vcsAccessTokenExpiryDate;
730-
}
731-
732500
public Set<TutorialGroupRegistration> getTutorialGroupRegistrations() {
733501
return tutorialGroupRegistrations;
734502
}
@@ -745,23 +513,6 @@ public void setPushNotificationDeviceConfigurations(Set<PushNotificationDeviceCo
745513
this.pushNotificationDeviceConfigurations = pushNotificationDeviceConfigurations;
746514
}
747515

748-
@Nullable
749-
public ZonedDateTime getSelectedLLMUsageTimestamp() {
750-
return aiSelectionDecisionDate;
751-
}
752-
753-
public void setSelectedLLMUsageTimestamp(@Nullable ZonedDateTime aiSelectionDecisionDate) {
754-
this.aiSelectionDecisionDate = aiSelectionDecisionDate;
755-
}
756-
757-
public AiSelectionDecision getSelectedLLMUsage() {
758-
return aiSelectionDecision;
759-
}
760-
761-
public void setSelectedLLMUsage(@Nullable AiSelectionDecision aiSelectionDecision) {
762-
this.aiSelectionDecision = aiSelectionDecision;
763-
}
764-
765516
public LearnerProfile getLearnerProfile() {
766517
return learnerProfile;
767518
}
@@ -783,11 +534,4 @@ public Bytes getExternalId() {
783534
return BytesConverter.longToBytes(this.getId());
784535
}
785536

786-
public boolean isMemirisEnabled() {
787-
return memirisEnabled;
788-
}
789-
790-
public void setMemirisEnabled(boolean memirisEnabled) {
791-
this.memirisEnabled = memirisEnabled;
792-
}
793537
}

src/main/java/de/tum/cit/aet/artemis/account/domain/UserRecoveryKey.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ public void setResetDate(@Nullable Instant resetDate) {
9696
}
9797

9898
/**
99-
* Whether nothing is outstanding any more, in which case the row can be removed rather than left as a row of nulls.
99+
* Whether nothing is outstanding, in which case the row can be removed rather than left as a row of nulls.
100100
*
101101
* @return true if neither key nor reset date is set
102102
*/

0 commit comments

Comments
 (0)