Skip to content

Commit 1361896

Browse files
committed
Merge branch 'main' into dev-yesitha
2 parents b620350 + ce8a723 commit 1361896

9 files changed

Lines changed: 328 additions & 1 deletion

File tree

README.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Learning Management System (LMS)
2+
## Overview
3+
4+
The LMS project is a **microservices-based application** designed to streamline learning and course management. It integrates various tools and technologies to ensure scalability, security, and efficiency.
5+
6+
7+
<img src="https://github.com/user-attachments/assets/976dda89-ba72-4595-86b5-29692c5207af" width="650" height="500" />
8+
9+
10+
11+
## Features
12+
13+
- **Payment Integration:** Supports payments through [PayHere](https://www.payhere.lk/).
14+
- **Microservices Architecture:** Built using Spring Cloud with centralized service discovery via **Eureka**.
15+
- **API Gateway:** Utilizes Spring Gateway for request routing and load balancing.
16+
- **Authentication & Authorization:** Secured with JWT token-based authentication and role-based access control.
17+
- **Content Delivery Network (CDN):** Uses AWS CloudFront with **Signed URLs** to restrict access by IP and provide time-limited links.
18+
- **Storage Solutions:**
19+
- **AWS S3:** Securely stores videos.
20+
- **Nextcloud:** Manages and stores other documents.
21+
- **Containerization:**
22+
- Docker images are created using the **Maven Jib plugin**.
23+
- **GitHub Actions** automate Docker image creation and push to DockerHub.
24+
- **Orchestration:** Configured with a Docker Compose file to simplify project setup and deployment.
25+
26+
27+
## Architecture
28+
29+
This project employs a microservices architecture with the following components:
30+
- **Eureka Server:** Centralized service registry for microservices.
31+
- **Spring Gateway:** Handles routing and authentication.
32+
- **Multiple Microservices:** Each handles specific functionalities, ensuring modularity and scalability.
33+
34+
35+
## Technologies Used
36+
37+
- Backend: Spring Boot, Spring Cloud, Eureka, Spring Gateway
38+
- Authentication: JWT Tokens
39+
- Storage: AWS S3, Nextcloud
40+
- Payment Gateway: PayHere
41+
- Containerization: Docker, Maven Jib Plugin
42+
- CI/CD: GitHub Actions

lib-global/src/main/java/com/itgura/util/ResourceManagementURI.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,5 @@ public class ResourceManagementURI {
3333
public static final String STUDENT_ID = "/{studentId}";
3434
public static final String ANSWERTOQUIZ = "/answer-to-quiz";
3535
public static final String USER_DETAILS = "/user-details";
36+
public static final String STREAM = "/stream";
3637
}

resource-management/resource-management-all/src/main/java/com/itgura/controller/MaterialController.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
import org.springframework.web.bind.annotation.*;
1818

1919
import java.util.UUID;
20-
20+
import java.util.List;
2121

2222
@RestController
2323
@RequestMapping(URIPrefix.API + URIPrefix.V1 + URIPathVariable.RESOURCE_MANAGEMENT)
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package com.itgura.controller;
2+
3+
import com.itgura.dto.AppResponse;
4+
import com.itgura.exception.ValueNotExistException;
5+
import com.itgura.response.dto.StreamResponseDto;
6+
import com.itgura.service.UserStreamService;
7+
import com.itgura.util.ResourceManagementURI;
8+
import com.itgura.util.URIPathVariable;
9+
import com.itgura.util.URIPrefix;
10+
import org.springframework.beans.factory.annotation.Autowired;
11+
import org.springframework.web.bind.annotation.*;
12+
13+
import java.util.List;
14+
import java.util.UUID;
15+
16+
@RestController
17+
@RequestMapping(URIPrefix.API + URIPrefix.V1 + URIPathVariable.RESOURCE_MANAGEMENT)
18+
public class StreamController {
19+
@Autowired
20+
private UserStreamService userStreamService;
21+
22+
@PostMapping(value = ResourceManagementURI.STREAM + URIPrefix.CREATE)
23+
public AppResponse<String> createStream(@RequestParam String stream) {
24+
try {
25+
String response = userStreamService.createStream(stream);
26+
return AppResponse.ok(response);
27+
} catch (Exception e) {
28+
return AppResponse.error(null, e.getMessage(), "Server Error", "500", "");
29+
}
30+
}
31+
32+
@DeleteMapping(value = ResourceManagementURI.STREAM + URIPrefix.DELETE + URIPrefix.ID)
33+
public AppResponse<String> deleteStream(@PathVariable UUID id) {
34+
try {
35+
String response = userStreamService.deleteStream(id);
36+
return AppResponse.ok(response);
37+
} catch (Exception e) {
38+
return AppResponse.error(null, e.getMessage(), "Server Error", "500", "");
39+
}
40+
}
41+
42+
@PatchMapping(value = ResourceManagementURI.STREAM + URIPrefix.UPDATE + URIPrefix.ID)
43+
public AppResponse<String> updateStream(@PathVariable UUID id, @RequestParam String stream) {
44+
try {
45+
String response = userStreamService.updateStream(id, stream);
46+
return AppResponse.ok(response);
47+
} catch (Exception e) {
48+
return AppResponse.error(null, e.getMessage(), "Server Error", "500", "");
49+
}
50+
}
51+
52+
@GetMapping(value = ResourceManagementURI.STREAM + URIPrefix.GET + URIPrefix.ID)
53+
public AppResponse<StreamResponseDto> getStreamById(@PathVariable UUID id) {
54+
try {
55+
StreamResponseDto response = userStreamService.getStreamById(id);
56+
return AppResponse.ok(response);
57+
} catch (ValueNotExistException e) {
58+
return AppResponse.error(null, e.getMessage(), "Value Not Found", "404", "");
59+
} catch (Exception e) {
60+
return AppResponse.error(null, e.getMessage(), "Server Error", "500", "");
61+
}
62+
}
63+
64+
@GetMapping(value = ResourceManagementURI.STREAM + URIPrefix.GET_ALL)
65+
public AppResponse<List<StreamResponseDto>> getAllStreams() {
66+
try {
67+
List<StreamResponseDto> response = userStreamService.getAllStreams();
68+
return AppResponse.ok(response);
69+
} catch (Exception e) {
70+
return AppResponse.error(null, e.getMessage(), "Server Error", "500", "");
71+
}
72+
}
73+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package com.itgura.response.dto;
2+
3+
import com.fasterxml.jackson.annotation.JsonProperty;
4+
import jakarta.persistence.Column;
5+
import lombok.AllArgsConstructor;
6+
import lombok.Builder;
7+
import lombok.Data;
8+
import lombok.NoArgsConstructor;
9+
10+
import java.util.UUID;
11+
@Data
12+
@AllArgsConstructor
13+
@NoArgsConstructor
14+
@Builder
15+
public class StreamResponseDto {
16+
@JsonProperty("stream_id")
17+
private UUID streamId;
18+
@JsonProperty("stream")
19+
private String stream;
20+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.itgura.response.dto.mapper;
2+
3+
import com.itgura.entity.MaterialType;
4+
import com.itgura.entity.Stream;
5+
import com.itgura.response.dto.MaterialTypeResponseDto;
6+
import com.itgura.response.dto.StreamResponseDto;
7+
import org.mapstruct.Mapper;
8+
import org.mapstruct.Mapping;
9+
import org.mapstruct.factory.Mappers;
10+
11+
import java.util.List;
12+
13+
@Mapper
14+
public interface StreamMapper {
15+
StreamMapper INSTANCE = Mappers.getMapper(StreamMapper.class);
16+
StreamResponseDto toDto(Stream stream);
17+
18+
List<StreamResponseDto> toDtoList(List<Stream> materialTypes);
19+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.itgura.service;
2+
3+
import com.itgura.exception.ValueNotExistException;
4+
import com.itgura.response.dto.StreamResponseDto;
5+
6+
import java.util.List;
7+
import java.util.UUID;
8+
9+
public interface UserStreamService {
10+
11+
String createStream(String stream);
12+
String deleteStream(UUID id);
13+
14+
String updateStream(UUID id, String stream);
15+
StreamResponseDto getStreamById(UUID id) throws ValueNotExistException;
16+
List<StreamResponseDto> getAllStreams() throws ValueNotExistException;
17+
}

resource-management/resource-management-service/src/main/java/com/itgura/service/impl/MaterialServiceImpl.java

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,40 @@ private String signPolicyWithPrivateKey(String base64EncodedPolicy) throws Excep
304304

305305
return Base64.getEncoder().encodeToString(signedBytes);
306306
}
307+
@Override
308+
public MaterialResponseDto getMaterialById(UUID materialId) {
309+
try {
310+
UserResponseDto loggedUserDetails = userDetailService.getLoggedUserDetails(UserUtil.extractToken());
311+
312+
if (loggedUserDetails == null) {
313+
throw new ValueNotExistException("User not found");
314+
}else{
315+
Material material = materialRepository.findById(materialId).orElseThrow(()
316+
-> new ValueNotExistException("Material not found with id " + materialId));
317+
MaterialResponseDto dto = MaterialMapper.INSTANCE.toDto(material);
318+
return dto;
319+
}
320+
}catch (Exception e) {
321+
throw new RuntimeException(e);
322+
}
323+
}
307324

325+
@Override
326+
public List<MaterialResponseDto> getAllMaterialBySessionId(UUID sessionId) {
327+
try {
328+
UserResponseDto loggedUserDetails = userDetailService.getLoggedUserDetails(UserUtil.extractToken());
329+
330+
if (loggedUserDetails == null) {
331+
throw new ValueNotExistException("User not found");
332+
}else{
333+
List<Material> allBySessionContentId = materialRepository.findAllBySession_ContentId(sessionId);
334+
List<MaterialResponseDto> dtos = MaterialMapper.INSTANCE.toDtoList(allBySessionContentId);
335+
return dtos;
336+
}
337+
}catch (Exception e) {
338+
throw new RuntimeException(e);
339+
}
340+
}
308341

309342
private String urlEncode(String value) {
310343

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
package com.itgura.service.impl;
2+
3+
import com.itgura.entity.Stream;
4+
import com.itgura.exception.ValueNotExistException;
5+
import com.itgura.repository.StreamRepository;
6+
import com.itgura.request.dto.UserResponseDto;
7+
import com.itgura.response.dto.StreamResponseDto;
8+
import com.itgura.response.dto.mapper.StreamMapper;
9+
import com.itgura.service.UserDetailService;
10+
import com.itgura.service.UserStreamService;
11+
import com.itgura.util.UserUtil;
12+
import jakarta.transaction.Transactional;
13+
import jakarta.ws.rs.ForbiddenException;
14+
import org.springframework.beans.factory.annotation.Autowired;
15+
import org.springframework.stereotype.Service;
16+
17+
import java.util.List;
18+
import java.util.Optional;
19+
import java.util.UUID;
20+
21+
@Service
22+
public class StreamServiceImpl implements UserStreamService {
23+
@Autowired
24+
private StreamRepository streamRepository;
25+
26+
@Autowired
27+
private UserDetailService userDetailService;
28+
29+
@Override
30+
@Transactional
31+
public String createStream(String stream) {
32+
try {
33+
UserResponseDto loggedUserDetails = userDetailService.getLoggedUserDetails(UserUtil.extractToken());
34+
if (loggedUserDetails == null) {
35+
throw new ValueNotExistException("User not found");
36+
}
37+
if (!(loggedUserDetails.getUserRoles().equals("ADMIN"))) {
38+
throw new ForbiddenException("User is not authorized to perform this operation");
39+
} else {
40+
Stream stream1 = new Stream();
41+
stream1.setStream(stream);
42+
streamRepository.save(stream1);
43+
return "Stream saved successfully";
44+
}
45+
} catch (Exception e) {
46+
throw new RuntimeException(e);
47+
}
48+
}
49+
50+
@Override
51+
@Transactional
52+
public String deleteStream(UUID id) {
53+
try {
54+
UserResponseDto loggedUserDetails = userDetailService.getLoggedUserDetails(UserUtil.extractToken());
55+
if (loggedUserDetails == null) {
56+
throw new ValueNotExistException("User not found");
57+
}
58+
if (!(loggedUserDetails.getUserRoles().equals("ADMIN"))) {
59+
throw new ForbiddenException("User is not authorized to perform this operation");
60+
} else {
61+
Optional<Stream> byId = streamRepository.findById(id);
62+
if (byId.isPresent()) {
63+
streamRepository.deleteById(id);
64+
return "Stream deleted successfully";
65+
} else {
66+
return "Stream not found with id: " + id;
67+
}
68+
}
69+
} catch (Exception e) {
70+
throw new RuntimeException(e);
71+
}
72+
}
73+
74+
@Override
75+
@Transactional
76+
public String updateStream(UUID id, String stream) {
77+
try {
78+
UserResponseDto loggedUserDetails = userDetailService.getLoggedUserDetails(UserUtil.extractToken());
79+
if (loggedUserDetails == null) {
80+
throw new ValueNotExistException("User not found");
81+
}
82+
if (!(loggedUserDetails.getUserRoles().equals("ADMIN"))) {
83+
throw new ForbiddenException("User is not authorized to perform this operation");
84+
} else {
85+
Optional<Stream> byId = streamRepository.findById(id);
86+
if (byId.isPresent()) {
87+
Stream stream1 = byId.get();
88+
stream1.setStream(stream);
89+
streamRepository.save(stream1);
90+
return "Stream updated successfully";
91+
} else {
92+
return "Stream not found with id: " + id;
93+
}
94+
}
95+
} catch (Exception e) {
96+
throw new RuntimeException(e);
97+
}
98+
}
99+
100+
@Override
101+
@Transactional
102+
public StreamResponseDto getStreamById(UUID id) throws ValueNotExistException {
103+
Optional<Stream> byId = streamRepository.findById(id);
104+
if (byId.isPresent()) {
105+
Stream stream1 = byId.get();
106+
return StreamMapper.INSTANCE.toDto(stream1);
107+
} else {
108+
throw new ValueNotExistException("Stream not found with id: " + id);
109+
}
110+
}
111+
112+
@Override
113+
@Transactional
114+
public List<StreamResponseDto> getAllStreams() throws ValueNotExistException {
115+
List<Stream> all = streamRepository.findAll();
116+
if (all.isEmpty()) {
117+
throw new ValueNotExistException("No streams found");
118+
} else {
119+
return StreamMapper.INSTANCE.toDtoList(all);
120+
}
121+
}
122+
}

0 commit comments

Comments
 (0)