Skip to content
Open
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
5 changes: 5 additions & 0 deletions RUN_TESTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,10 @@ docker compose up --build
Тестовые данные для локальной БД загружаются отдельно:

```bash
chmod +x scripts/seed-test-data.sh
chmod +x scripts/upload-test-photos.sh
./scripts/seed-test-data.sh
./scripts/upload-test-photos.sh
```

Перед сидированием лучше пересобрать контейнер. Для загрузки фотографий необходимо установить `aws cli`, если его еще нет.
2 changes: 2 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springframework.boot:spring-boot-starter-webflux'
implementation 'org.flywaydb:flyway-core'
implementation 'org.flywaydb:flyway-database-postgresql'
implementation platform("software.amazon.awssdk:bom:2.25.0")
implementation "software.amazon.awssdk:s3"

Expand Down
File renamed without changes
Binary file added scripts/test-photos/curb.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes
File renamed without changes
File renamed without changes
1 change: 1 addition & 0 deletions src/main/java/goodroad/model/Role.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

public enum Role {
USER,
VOLUNTEER,
MODERATOR,
MODERATOR_ADMIN
}
1 change: 1 addition & 0 deletions src/main/java/goodroad/security/SecurityConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ public SecurityFilterChain chain(HttpSecurity http) throws Exception {
//.requestMatchers("/users/moderators/{id}").hasAnyRole("MODERATOR", "MODERATOR_ADMIN") // TODO: возможно пересмотреть права пользователей на этот ендпоинт
.requestMatchers("/users/moderators/**").hasRole("MODERATOR_ADMIN")
.requestMatchers("/reviews/moderation/**").hasAnyRole("MODERATOR", "MODERATOR_ADMIN")
.requestMatchers("/volunteer/moderation/**").hasAnyRole("MODERATOR", "MODERATOR_ADMIN")
.anyRequest().authenticated()
)
.build();
Expand Down
31 changes: 31 additions & 0 deletions src/main/java/goodroad/storage/StorageService.java
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,37 @@ public String uploadReviewPhoto(MultipartFile file, String userId) {
}
}

public String uploadVolunteerCertificate(MultipartFile file, String userId) {

try {

String ext = getExt(file.getOriginalFilename());

String key = "volunteer-certificates/"
+ userId
+ "/"
+ UUID.randomUUID()
+ ext;

s3Client.putObject(
PutObjectRequest.builder()
.bucket(bucket)
.key(key)
.contentType(file.getContentType())
.build(),
RequestBody.fromBytes(file.getBytes())
);

return "https://storage.yandexcloud.net/"
+ bucket
+ "/"
+ key;

} catch (Exception e) {
throw new RuntimeException("Upload failed", e);
}
}

private String getExt(String name) {
if (name == null) return "";
int i = name.lastIndexOf(".");
Expand Down
112 changes: 112 additions & 0 deletions src/main/java/goodroad/volunteer/VolunteerController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
package goodroad.volunteer;

import lombok.RequiredArgsConstructor;
import org.springframework.http.MediaType;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.util.List;

@RestController
@RequestMapping("/volunteer")
@RequiredArgsConstructor
public class VolunteerController {
private final VolunteerService service;

@GetMapping("/menu")
public VolunteerService.VolunteerMenuResp getMenu(Authentication authentication) {
return service.getMenu(authentication.getName());
}

@PostMapping("/applications")
public VolunteerService.VolunteerApplicationResp createApplication(
Authentication authentication,
@RequestBody VolunteerService.CreateVolunteerApplicationReq req
) {
return service.createApplication(authentication.getName(), req);
}

@PostMapping(value = "/applications/photos", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public VolunteerService.PhotoUploadResp uploadCertificate(
Authentication authentication,
@RequestParam("file") MultipartFile file
) {
return service.uploadCertificate(authentication.getName(), file);
}

@GetMapping("/requests/own")
public List<VolunteerService.HelpRequestResp> listOwnRequests(Authentication authentication) {
return service.listOwnRequests(authentication.getName());
}

@PostMapping("/requests")
public VolunteerService.HelpRequestResp createHelpRequest(
Authentication authentication,
@RequestBody VolunteerService.HelpRequestReq req
) {
return service.createHelpRequest(authentication.getName(), req);
}

@GetMapping("/requests/available")
public List<VolunteerService.HelpRequestResp> listAvailableRequests(
Authentication authentication,
@RequestParam(required = false) Double latitude,
@RequestParam(required = false) Double longitude
) {
return service.listAvailableRequests(authentication.getName(), latitude, longitude);
}

@GetMapping("/requests/my-wards")
public List<VolunteerService.HelpRequestResp> listMyWards(Authentication authentication) {
return service.listMyWards(authentication.getName());
}

@GetMapping("/requests/{id}")
public VolunteerService.HelpRequestResp getHelpRequest(Authentication authentication, @PathVariable String id) {
return service.getHelpRequest(authentication.getName(), id);
}

@PostMapping("/requests/{id}/accept")
public VolunteerService.HelpRequestResp acceptRequest(Authentication authentication, @PathVariable String id) {
return service.acceptRequest(authentication.getName(), id);
}

@PostMapping("/requests/{id}/withdraw")
public VolunteerService.HelpRequestResp withdrawResponse(Authentication authentication, @PathVariable String id) {
return service.withdrawResponse(authentication.getName(), id);
}

@PostMapping("/requests/{id}/cancel")
public VolunteerService.HelpRequestResp cancelOwnRequest(Authentication authentication, @PathVariable String id) {
return service.cancelOwnRequest(authentication.getName(), id);
}

@DeleteMapping("/requests/{id}")
public void deleteOwnRequest(Authentication authentication, @PathVariable String id) {
service.deleteOwnRequest(authentication.getName(), id);
}

@PostMapping("/requests/{id}/route")
public VolunteerService.HelpRequestResp setWalkRoute(
Authentication authentication,
@PathVariable String id,
@RequestBody VolunteerService.WalkRouteReq req
) {
return service.setWalkRoute(authentication.getName(), id, req);
}

@PostMapping("/requests/{id}/start")
public VolunteerService.HelpRequestResp startWalk(
Authentication authentication,
@PathVariable String id,
@RequestBody(required = false) VolunteerService.WalkRouteReq req
) {
return service.startWalk(authentication.getName(), id, req);
}

@PostMapping("/requests/{id}/finish")
public VolunteerService.HelpRequestResp finishWalk(Authentication authentication, @PathVariable String id) {
return service.finishWalk(authentication.getName(), id);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package goodroad.volunteer;

import lombok.RequiredArgsConstructor;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/volunteer/moderation")
@RequiredArgsConstructor
public class VolunteerModerationController {
private final VolunteerService service;

@GetMapping("/applications/pending")
public List<VolunteerService.VolunteerApplicationResp> listPendingApplications() {
return service.listPendingApplications();
}

@PostMapping("/applications/{id}/approve")
public VolunteerService.VolunteerApplicationResp approveApplication(Authentication authentication, @PathVariable String id) {
return service.approveApplication(authentication.getName(), id);
}

@PostMapping("/applications/{id}/reject")
public VolunteerService.VolunteerApplicationResp rejectApplication(
Authentication authentication,
@PathVariable String id,
@RequestBody VolunteerService.RejectApplicationReq req
) {
return service.rejectApplication(authentication.getName(), id, req);
}
}
Loading