UsersController.java

1
package edu.ucsb.cs156.dining.controllers;
2
3
import com.fasterxml.jackson.core.JsonProcessingException;
4
import com.fasterxml.jackson.databind.ObjectMapper;
5
import edu.ucsb.cs156.dining.entities.Admin;
6
import edu.ucsb.cs156.dining.entities.Moderator;
7
import edu.ucsb.cs156.dining.entities.User;
8
import edu.ucsb.cs156.dining.errors.EntityNotFoundException;
9
import edu.ucsb.cs156.dining.models.CurrentUser;
10
import edu.ucsb.cs156.dining.models.UserDTO;
11
import edu.ucsb.cs156.dining.repositories.AdminRepository;
12
import edu.ucsb.cs156.dining.repositories.ModeratorRepository;
13
import edu.ucsb.cs156.dining.repositories.UserRepository;
14
import edu.ucsb.cs156.dining.statuses.ModerationStatus;
15
import io.swagger.v3.oas.annotations.Operation;
16
import io.swagger.v3.oas.annotations.tags.Tag;
17
import java.time.LocalDate;
18
import java.util.ArrayList;
19
import java.util.List;
20
import java.util.stream.StreamSupport;
21
import org.springframework.beans.factory.annotation.Autowired;
22
import org.springframework.beans.factory.annotation.Value;
23
import org.springframework.http.HttpStatus;
24
import org.springframework.http.ResponseEntity;
25
import org.springframework.security.access.prepost.PreAuthorize;
26
import org.springframework.web.bind.annotation.*;
27
import org.springframework.web.bind.annotation.GetMapping;
28
import org.springframework.web.bind.annotation.RequestMapping;
29
import org.springframework.web.bind.annotation.RestController;
30
import org.springframework.web.server.ResponseStatusException;
31
32
/**
33
 * This is a REST controller for getting information about the users.
34
 *
35
 * <p>These endpoints are only accessible to users with the role "ROLE_ADMIN".
36
 */
37
@Tag(name = "User information (admin only)")
38
@RequestMapping("/api")
39
@RestController
40
public class UsersController extends ApiController {
41
42
  @Value("#{'${app.admin.emails}'.split(',')}")
43
  private final List<String> adminEmails = new ArrayList<>();
44
45
  @Autowired UserRepository userRepository;
46
47
  @Autowired AdminRepository adminRepository;
48
49
  @Autowired ModeratorRepository moderatorRepository;
50
51
  @Autowired ObjectMapper mapper;
52
53
  /**
54
   * This method returns a list of all users. Accessible only to users with the role "ROLE_ADMIN".
55
   *
56
   * @return a list of all users
57
   * @throws JsonProcessingException if there is an error processing the JSON
58
   */
59
  @Operation(summary = "Get a list of all users")
60
  @PreAuthorize("hasRole('ROLE_ADMIN')")
61
  @GetMapping("/admin/users")
62
  public ResponseEntity<String> users() throws JsonProcessingException {
63
64
    Iterable<User> users = userRepository.findAll();
65
    List<UserDTO> userDTOs =
66
        StreamSupport.stream(users.spliterator(), false).map(this::userDTO).toList();
67
    String body = mapper.writeValueAsString(userDTOs);
68 1 1. users : replaced return value with null for edu/ucsb/cs156/dining/controllers/UsersController::users → KILLED
    return ResponseEntity.ok().body(body);
69
  }
70
71
  /**
72
   * This method returns list of all users with a proposed alias.
73
   *
74
   * @return a list of users with a proposed alias
75
   * @throws JsonProcessingException if there is an error processing the JSON
76
   */
77
  @Operation(summary = "Get a list of all users with a proposed alias")
78
  @PreAuthorize("hasRole('ROLE_ADMIN')")
79
  @GetMapping("/admin/usersWithProposedAlias")
80
  public ResponseEntity<String> getUsersWithProposedAlias() throws JsonProcessingException {
81
    Iterable<User> users = userRepository.findByProposedAliasNotNull();
82
    String body = mapper.writeValueAsString(users);
83 1 1. getUsersWithProposedAlias : replaced return value with null for edu/ucsb/cs156/dining/controllers/UsersController::getUsersWithProposedAlias → KILLED
    return ResponseEntity.ok().body(body);
84
  }
85
86
  /** Get all users whose proposed alias is awaiting moderation. */
87
  @Operation(summary = "Get all aliases needing moderation")
88
  @PreAuthorize("hasAnyRole('ROLE_ADMIN','ROLE_MODERATOR')")
89
  @GetMapping("/admin/users/needsmoderation")
90
  public ResponseEntity<String> getAliasesNeedingModeration() throws JsonProcessingException {
91
92
    Iterable<User> users =
93
        userRepository.findByStatusAndProposedAliasNotNull(ModerationStatus.AWAITING_REVIEW);
94
95
    String body = mapper.writeValueAsString(users);
96
97 1 1. getAliasesNeedingModeration : replaced return value with null for edu/ucsb/cs156/dining/controllers/UsersController::getAliasesNeedingModeration → KILLED
    return ResponseEntity.ok().body(body);
98
  }
99
100
  /**
101
   * This method allows the user to update their alias.
102
   *
103
   * @param proposedAlias the new alias
104
   * @return the updated user
105
   */
106
  @Operation(summary = "Update proposed alias of the current user")
107
  @PreAuthorize("hasRole('ROLE_USER')")
108
  @PostMapping("/currentUser/updateAlias")
109
  public ResponseEntity<User> updateProposedAlias(@RequestParam String proposedAlias) {
110
    CurrentUser currentUser = super.getCurrentUser();
111
    User user = currentUser.getUser();
112
113 1 1. updateProposedAlias : negated conditional → KILLED
    if (userRepository.findByAlias(proposedAlias).isPresent()) {
114
      throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Alias already in use.");
115
    }
116
117 1 1. updateProposedAlias : removed call to edu/ucsb/cs156/dining/entities/User::setProposedAlias → KILLED
    user.setProposedAlias(proposedAlias);
118 1 1. updateProposedAlias : removed call to edu/ucsb/cs156/dining/entities/User::setStatus → KILLED
    user.setStatus(ModerationStatus.AWAITING_REVIEW);
119
    User savedUser = userRepository.save(user);
120
121 1 1. updateProposedAlias : replaced return value with null for edu/ucsb/cs156/dining/controllers/UsersController::updateProposedAlias → KILLED
    return ResponseEntity.ok(savedUser);
122
  }
123
124
  /**
125
   * This method allows an admin to update the moderation status of a user's alias.
126
   *
127
   * @param id the id of the user to update
128
   * @param approved the new moderation status
129
   * @return the updated user
130
   */
131
  @PreAuthorize("hasAnyRole('ROLE_ADMIN','ROLE_MODERATOR')")
132
  @PutMapping("/currentUser/updateAliasModeration")
133
  public User updateAliasModeration(@RequestParam long id, @RequestParam Boolean approved) {
134
135
    User user =
136 1 1. lambda$updateAliasModeration$0 : replaced return value with null for edu/ucsb/cs156/dining/controllers/UsersController::lambda$updateAliasModeration$0 → KILLED
        userRepository.findById(id).orElseThrow(() -> new EntityNotFoundException(User.class, id));
137
138 1 1. updateAliasModeration : negated conditional → KILLED
    if (approved) {
139 1 1. updateAliasModeration : removed call to edu/ucsb/cs156/dining/entities/User::setAlias → KILLED
      user.setAlias(user.getProposedAlias());
140 1 1. updateAliasModeration : removed call to edu/ucsb/cs156/dining/entities/User::setStatus → KILLED
      user.setStatus(ModerationStatus.APPROVED);
141 1 1. updateAliasModeration : removed call to edu/ucsb/cs156/dining/entities/User::setDateApproved → KILLED
      user.setDateApproved(LocalDate.now());
142 1 1. updateAliasModeration : removed call to edu/ucsb/cs156/dining/entities/User::setProposedAlias → KILLED
      user.setProposedAlias(null);
143
    } else {
144 1 1. updateAliasModeration : removed call to edu/ucsb/cs156/dining/entities/User::setStatus → KILLED
      user.setStatus(ModerationStatus.REJECTED);
145
    }
146
147
    userRepository.save(user);
148
149 1 1. updateAliasModeration : replaced return value with null for edu/ucsb/cs156/dining/controllers/UsersController::updateAliasModeration → KILLED
    return user;
150
  }
151
152
  /**
153
   * This method allows an admin to toggle whether a user's email appears in the admin table. Will
154
   * not toggle emails from adminEmails.
155
   *
156
   * @param id the id of the user to toggle
157
   * @return the updated user
158
   */
159
  @PreAuthorize("hasRole('ROLE_ADMIN')")
160
  @PutMapping("/admin/toggleAdmin")
161
  public UserDTO toggleAdminStatus(@RequestParam long id) {
162
163
    User user =
164 1 1. lambda$toggleAdminStatus$1 : replaced return value with null for edu/ucsb/cs156/dining/controllers/UsersController::lambda$toggleAdminStatus$1 → KILLED
        userRepository.findById(id).orElseThrow(() -> new EntityNotFoundException(User.class, id));
165
166 1 1. toggleAdminStatus : negated conditional → KILLED
    if (!adminEmails.contains(user.getEmail())) {
167
      boolean isAdmin = adminRepository.existsByEmail(user.getEmail());
168 1 1. toggleAdminStatus : negated conditional → KILLED
      if (isAdmin) adminRepository.deleteByEmail(user.getEmail());
169
      else adminRepository.save(new Admin(user.getEmail()));
170
    }
171
172 1 1. toggleAdminStatus : replaced return value with null for edu/ucsb/cs156/dining/controllers/UsersController::toggleAdminStatus → KILLED
    return userDTO(user);
173
  }
174
175
  /**
176
   * This method allows an admin to toggle whether a user's email appears in the moderator table.
177
   *
178
   * @param id the id of the user to toggle
179
   * @return the updated user
180
   */
181
  @PreAuthorize("hasRole('ROLE_ADMIN')")
182
  @PutMapping("/admin/toggleModerator")
183
  public UserDTO toggleModeratorStatus(@RequestParam long id) {
184
185
    User user =
186 1 1. lambda$toggleModeratorStatus$2 : replaced return value with null for edu/ucsb/cs156/dining/controllers/UsersController::lambda$toggleModeratorStatus$2 → KILLED
        userRepository.findById(id).orElseThrow(() -> new EntityNotFoundException(User.class, id));
187
188
    boolean isModerator = moderatorRepository.existsByEmail(user.getEmail());
189 1 1. toggleModeratorStatus : negated conditional → KILLED
    if (isModerator) moderatorRepository.deleteByEmail(user.getEmail());
190
    else moderatorRepository.save(new Moderator(user.getEmail()));
191
192 1 1. toggleModeratorStatus : replaced return value with null for edu/ucsb/cs156/dining/controllers/UsersController::toggleModeratorStatus → KILLED
    return userDTO(user);
193
  }
194
195
  private UserDTO userDTO(User user) {
196
    String email = user.getEmail();
197 2 1. userDTO : negated conditional → KILLED
2. userDTO : negated conditional → KILLED
    boolean isAdmin = adminEmails.contains(email) || adminRepository.existsByEmail(email);
198
    boolean isModerator = moderatorRepository.existsByEmail(email);
199 1 1. userDTO : replaced return value with null for edu/ucsb/cs156/dining/controllers/UsersController::userDTO → KILLED
    return new UserDTO(user, isAdmin, isModerator);
200
  }
201
}

Mutations

68

1.1
Location : users
Killed by : edu.ucsb.cs156.dining.controllers.UsersControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.dining.controllers.UsersControllerTests]/[method:users__admin_logged_in()]
replaced return value with null for edu/ucsb/cs156/dining/controllers/UsersController::users → KILLED

83

1.1
Location : getUsersWithProposedAlias
Killed by : edu.ucsb.cs156.dining.controllers.UsersControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.dining.controllers.UsersControllerTests]/[method:admin_can_get_all_users_with_proposed_alias()]
replaced return value with null for edu/ucsb/cs156/dining/controllers/UsersController::getUsersWithProposedAlias → KILLED

97

1.1
Location : getAliasesNeedingModeration
Killed by : edu.ucsb.cs156.dining.controllers.UsersControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.dining.controllers.UsersControllerTests]/[method:admin_gets_empty_list_if_no_aliases_need_moderation()]
replaced return value with null for edu/ucsb/cs156/dining/controllers/UsersController::getAliasesNeedingModeration → KILLED

113

1.1
Location : updateProposedAlias
Killed by : edu.ucsb.cs156.dining.controllers.UsersControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.dining.controllers.UsersControllerTests]/[method:user_cannot_post_existing_alias()]
negated conditional → KILLED

117

1.1
Location : updateProposedAlias
Killed by : edu.ucsb.cs156.dining.controllers.UsersControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.dining.controllers.UsersControllerTests]/[method:a_user_can_post_a_new_alias()]
removed call to edu/ucsb/cs156/dining/entities/User::setProposedAlias → KILLED

118

1.1
Location : updateProposedAlias
Killed by : edu.ucsb.cs156.dining.controllers.UsersControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.dining.controllers.UsersControllerTests]/[method:a_user_can_post_a_new_alias()]
removed call to edu/ucsb/cs156/dining/entities/User::setStatus → KILLED

121

1.1
Location : updateProposedAlias
Killed by : edu.ucsb.cs156.dining.controllers.UsersControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.dining.controllers.UsersControllerTests]/[method:a_user_can_post_a_new_alias()]
replaced return value with null for edu/ucsb/cs156/dining/controllers/UsersController::updateProposedAlias → KILLED

136

1.1
Location : lambda$updateAliasModeration$0
Killed by : edu.ucsb.cs156.dining.controllers.UsersControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.dining.controllers.UsersControllerTests]/[method:admin_cannot_approve_nonexistent_user()]
replaced return value with null for edu/ucsb/cs156/dining/controllers/UsersController::lambda$updateAliasModeration$0 → KILLED

138

1.1
Location : updateAliasModeration
Killed by : edu.ucsb.cs156.dining.controllers.UsersControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.dining.controllers.UsersControllerTests]/[method:admin_can_approve_proposed_alias()]
negated conditional → KILLED

139

1.1
Location : updateAliasModeration
Killed by : edu.ucsb.cs156.dining.controllers.UsersControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.dining.controllers.UsersControllerTests]/[method:admin_can_approve_proposed_alias()]
removed call to edu/ucsb/cs156/dining/entities/User::setAlias → KILLED

140

1.1
Location : updateAliasModeration
Killed by : edu.ucsb.cs156.dining.controllers.UsersControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.dining.controllers.UsersControllerTests]/[method:admin_can_approve_proposed_alias()]
removed call to edu/ucsb/cs156/dining/entities/User::setStatus → KILLED

141

1.1
Location : updateAliasModeration
Killed by : edu.ucsb.cs156.dining.controllers.UsersControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.dining.controllers.UsersControllerTests]/[method:admin_can_approve_proposed_alias()]
removed call to edu/ucsb/cs156/dining/entities/User::setDateApproved → KILLED

142

1.1
Location : updateAliasModeration
Killed by : edu.ucsb.cs156.dining.controllers.UsersControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.dining.controllers.UsersControllerTests]/[method:admin_can_approve_proposed_alias()]
removed call to edu/ucsb/cs156/dining/entities/User::setProposedAlias → KILLED

144

1.1
Location : updateAliasModeration
Killed by : edu.ucsb.cs156.dining.controllers.UsersControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.dining.controllers.UsersControllerTests]/[method:admin_does_not_approve_alias()]
removed call to edu/ucsb/cs156/dining/entities/User::setStatus → KILLED

149

1.1
Location : updateAliasModeration
Killed by : edu.ucsb.cs156.dining.controllers.UsersControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.dining.controllers.UsersControllerTests]/[method:admin_can_approve_proposed_alias()]
replaced return value with null for edu/ucsb/cs156/dining/controllers/UsersController::updateAliasModeration → KILLED

164

1.1
Location : lambda$toggleAdminStatus$1
Killed by : edu.ucsb.cs156.dining.controllers.UsersControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.dining.controllers.UsersControllerTests]/[method:admin_cannot_toggle_admin_of_nonexistent_user()]
replaced return value with null for edu/ucsb/cs156/dining/controllers/UsersController::lambda$toggleAdminStatus$1 → KILLED

166

1.1
Location : toggleAdminStatus
Killed by : edu.ucsb.cs156.dining.controllers.UsersControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.dining.controllers.UsersControllerTests]/[method:admin_can_remove_user_from_admin_table()]
negated conditional → KILLED

168

1.1
Location : toggleAdminStatus
Killed by : edu.ucsb.cs156.dining.controllers.UsersControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.dining.controllers.UsersControllerTests]/[method:admin_can_remove_user_from_admin_table()]
negated conditional → KILLED

172

1.1
Location : toggleAdminStatus
Killed by : edu.ucsb.cs156.dining.controllers.UsersControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.dining.controllers.UsersControllerTests]/[method:admin_cannot_toggle_admin_of_super_admin()]
replaced return value with null for edu/ucsb/cs156/dining/controllers/UsersController::toggleAdminStatus → KILLED

186

1.1
Location : lambda$toggleModeratorStatus$2
Killed by : edu.ucsb.cs156.dining.controllers.UsersControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.dining.controllers.UsersControllerTests]/[method:admin_cannot_toggle_moderator_of_nonexistent_user()]
replaced return value with null for edu/ucsb/cs156/dining/controllers/UsersController::lambda$toggleModeratorStatus$2 → KILLED

189

1.1
Location : toggleModeratorStatus
Killed by : edu.ucsb.cs156.dining.controllers.UsersControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.dining.controllers.UsersControllerTests]/[method:admin_can_remove_user_from_moderator_table()]
negated conditional → KILLED

192

1.1
Location : toggleModeratorStatus
Killed by : edu.ucsb.cs156.dining.controllers.UsersControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.dining.controllers.UsersControllerTests]/[method:admin_can_remove_user_from_moderator_table()]
replaced return value with null for edu/ucsb/cs156/dining/controllers/UsersController::toggleModeratorStatus → KILLED

197

1.1
Location : userDTO
Killed by : edu.ucsb.cs156.dining.controllers.UsersControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.dining.controllers.UsersControllerTests]/[method:admin_cannot_toggle_admin_of_super_admin()]
negated conditional → KILLED

2.2
Location : userDTO
Killed by : edu.ucsb.cs156.dining.controllers.UsersControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.dining.controllers.UsersControllerTests]/[method:admin_can_remove_user_from_moderator_table()]
negated conditional → KILLED

199

1.1
Location : userDTO
Killed by : edu.ucsb.cs156.dining.controllers.UsersControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.dining.controllers.UsersControllerTests]/[method:admin_cannot_toggle_admin_of_super_admin()]
replaced return value with null for edu/ucsb/cs156/dining/controllers/UsersController::userDTO → KILLED

Active mutators

Tests examined


Report generated by PIT 1.17.0