-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #42 from alejandrocalleja/develop
v1.0 release
- Loading branch information
Showing
163 changed files
with
12,205 additions
and
615 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,55 @@ | ||
# PBL5 | ||
PBL5 | ||
<p align="center"> | ||
<img width="250px" src="https://github.com/alejandrocalleja/PBL5/blob/develop/src/main/resources/static/images/DeckLearn.png?raw=true" align="center" alt="GitHub Readme Stats" /> | ||
<h2 align="center">Deck Learn</h2> | ||
<p align="center">A spaced repetition based learning application</p> | ||
</p> | ||
|
||
<p align="center"> | ||
<a href="https://github.com/anuraghazra/github-readme-stats/actions"> | ||
<img alt="Tests Passing" src="https://github.com/anuraghazra/github-readme-stats/workflows/Test/badge.svg" /> | ||
</a> | ||
<a href="https://codecov.io/gh/anuraghazra/github-readme-stats"> | ||
<img src="https://codecov.io/gh/anuraghazra/github-readme-stats/branch/master/graph/badge.svg" /> | ||
</a> | ||
<a href="https://github.com/anuraghazra/github-readme-stats/issues"> | ||
<img alt="Issues" src="https://img.shields.io/github/issues/anuraghazra/github-readme-stats?color=0088ff" /> | ||
</a> | ||
<a href="https://github.com/anuraghazra/github-readme-stats/pulls"> | ||
<img alt="GitHub pull requests" src="https://img.shields.io/github/issues-pr/anuraghazra/github-readme-stats?color=0088ff" /> | ||
</a> | ||
</p> | ||
|
||
## Description | ||
Learning is an everyday necessity worldwide, which needs to be done the correct way | ||
to be effective. Information tends to fade in what is known as “the forgetting curve”, a problem | ||
that concerns a wide range of population. However, the fading of the data can be reverted and | ||
stabilised by means of various techniques. One that can be used to achieve a good procure of | ||
knowledge is spaced repetition. This method has been demonstrated to provide a sustainable | ||
capacity of memorization for its users. One of the many ways of using it is by means of the | ||
Leitner system, a flashcard approach that determines when is necessary to regain certain | ||
knowledge. Those flashcards are composed by a question and its answer, storing cards of the | ||
same topic in decks. Spaced repetition does not usually consider the motivation of the user. | ||
However, as it is highly important to maintain the user comfortable, gamification has been | ||
introduced to fulfil that purpose. Due to the importance of providing social interaction, a social | ||
network-like approach has been embraced by the application. Due to the importance of fulfilling | ||
the 2030 agenda of the United Nations, considering the SDGs has also been relevant. This work | ||
explains the development of the product, named DeckLearn, as well as its impact towards the | ||
established objectives and working hypotheses. | ||
|
||
## Used technologies | ||
* [![image](https://img.shields.io/badge/Spring_Boot-F2F4F9?style=for-the-badge&logo=spring-boot)](https://spring.io/projects/spring-boot) | ||
* [Thymeleaf](https://www.thymeleaf.org/) | ||
* [![image](https://img.shields.io/badge/Hibernate-59666C?style=for-the-badge&logo=Hibernate&logoColor=white)](https://hibernate.org/) | ||
* [![image](https://img.shields.io/badge/Jenkins-D24939?style=for-the-badge&logo=Jenkins&logoColor=white)](https://www.jenkins.io/) | ||
* [![image](https://img.shields.io/badge/Nginx-009639?style=for-the-badge&logo=nginx&logoColor=white)](https://www.nginx.com/) | ||
* [Sonarqube](https://www.sonarqube.org/) | ||
|
||
|
||
## CI/CD | ||
|
||
## | ||
|
||
## Contributing | ||
Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change. | ||
|
||
Please make sure to update tests as appropriate. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
223 changes: 223 additions & 0 deletions
223
src/main/java/eus/blankcard/decklearn/controller/DeckController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,223 @@ | ||
package eus.blankcard.decklearn.controller; | ||
|
||
import java.sql.Time; | ||
import java.text.SimpleDateFormat; | ||
import java.util.ArrayList; | ||
import java.util.Optional; | ||
import java.util.concurrent.atomic.AtomicInteger; | ||
|
||
import javax.servlet.http.HttpServletRequest; | ||
import javax.servlet.http.HttpServletResponse; | ||
|
||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.security.core.Authentication; | ||
import org.springframework.security.core.context.SecurityContextHolder; | ||
import org.springframework.stereotype.Controller; | ||
import org.springframework.web.bind.annotation.GetMapping; | ||
import org.springframework.web.bind.annotation.PathVariable; | ||
import org.springframework.web.bind.annotation.PostMapping; | ||
|
||
import eus.blankcard.decklearn.models.deck.DeckModel; | ||
import eus.blankcard.decklearn.models.user.UserModel; | ||
import eus.blankcard.decklearn.repository.deck.DeckRepository; | ||
import eus.blankcard.decklearn.repository.user.UserRepository; | ||
import eus.blankcard.decklearn.util.DeckCreationUtils; | ||
import eus.blankcard.decklearn.util.StatsCalculator; | ||
|
||
@Controller | ||
public class DeckController { | ||
|
||
@Autowired | ||
UserRepository userRepository; | ||
|
||
@Autowired | ||
DeckRepository deckRepository; | ||
|
||
@Autowired | ||
DeckCreationUtils deckCreationUtils; | ||
|
||
@Autowired | ||
StatsCalculator statsCalculator; | ||
|
||
String redirectError = "redirect:/error"; | ||
|
||
@GetMapping("/deck/{deckId}") | ||
public String getMethodName(@PathVariable("deckId") Integer deckId, HttpServletRequest req, | ||
HttpServletResponse response) { | ||
|
||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); | ||
String loggedUsername = authentication.getName(); | ||
|
||
UserModel loggedUser = userRepository.findByUsername(loggedUsername); | ||
|
||
DeckModel deck = deckRepository.getById(deckId); | ||
UserModel creator = deck.getCreator(); | ||
|
||
req.setAttribute("deck", deck); | ||
req.setAttribute("cardNumber", deck.getCards().size()); | ||
req.setAttribute("types", deck.getTypes()); | ||
req.setAttribute("creator", creator.getUsername()); | ||
req.setAttribute("studies", deck.getTrainings().size()); | ||
req.setAttribute("home", true); | ||
req.setAttribute("saved", loggedUser.getSavedDecks().contains(deck)); | ||
req.setAttribute("isCreator", loggedUser.getDecks().contains(deck)); | ||
|
||
return "/deck/deck_view"; | ||
} | ||
|
||
@GetMapping("/deck/{deckId}/stats") | ||
public String getDeckStats(@PathVariable("deckId") Integer deckId, HttpServletRequest req, | ||
HttpServletResponse response) { | ||
DeckModel deck = deckRepository.getById(deckId); | ||
|
||
AtomicInteger monthStudies = statsCalculator.getMonthStudies(deck); | ||
int totalStudies = deck.getTrainings().size(); | ||
Time avgTime = statsCalculator.getAvgResponseTime(deck); | ||
String timeFormat = new SimpleDateFormat("mm:ss").format(avgTime); | ||
|
||
int totalSaves = deck.getSavers().size(); | ||
int averagePass = statsCalculator.getAveragePassRatio(deck); | ||
|
||
req.setAttribute("deck", deck); | ||
req.setAttribute("monthStudies", monthStudies); | ||
req.setAttribute("totalStudies", totalStudies); | ||
req.setAttribute("avgTime", timeFormat); | ||
req.setAttribute("totalSaves", totalSaves); | ||
req.setAttribute("averagePass", averagePass); | ||
req.setAttribute("stats", true); | ||
|
||
return "/deck/deck_stats"; | ||
} | ||
|
||
@PostMapping("/deck/{deckId}/save") | ||
public String saveDeck(@PathVariable("deckId") Integer deckId, HttpServletRequest req, | ||
HttpServletResponse response) { | ||
|
||
Optional<DeckModel> optionalDeck = deckRepository.findById(deckId); | ||
|
||
if (optionalDeck.isPresent()) { | ||
DeckModel deckModel = optionalDeck.get(); | ||
|
||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); | ||
String loggedUsername = authentication.getName(); | ||
|
||
UserModel userModel = userRepository.findByUsername(loggedUsername); | ||
|
||
if (userModel.getSavedDecks().contains(deckModel)) { | ||
userModel.getSavedDecks().remove(deckModel); | ||
} else { | ||
userModel.getSavedDecks().add(deckModel); | ||
} | ||
|
||
userRepository.save(userModel); | ||
|
||
return "redirect:/deck/" + deckModel.getId(); | ||
} else { | ||
return redirectError; | ||
} | ||
} | ||
|
||
@PostMapping("/deck/{deckId}/remove") | ||
public String deleteDeck(@PathVariable("deckId") Integer deckId, HttpServletRequest req, | ||
HttpServletResponse response) { | ||
|
||
Optional<DeckModel> optionalDeck = deckRepository.findById(deckId); | ||
|
||
if (optionalDeck.isPresent()) { | ||
DeckModel deck = optionalDeck.get(); | ||
|
||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); | ||
String loggedUsername = authentication.getName(); | ||
|
||
UserModel loggedUser = userRepository.findByUsername(loggedUsername); | ||
|
||
if (deck.getCreator().getId().equals(loggedUser.getId())) { | ||
deckRepository.delete(deck); | ||
} else { | ||
return redirectError; | ||
} | ||
|
||
return "redirect:/" + loggedUsername; | ||
|
||
} else { | ||
return redirectError; | ||
} | ||
} | ||
|
||
@GetMapping("/create/deck") | ||
public String getCreationForm(HttpServletRequest req, | ||
HttpServletResponse response) { | ||
|
||
DeckModel deck = new DeckModel(); | ||
deck.setCards(new ArrayList<>()); | ||
|
||
req.setAttribute("deck", deck); | ||
req.setAttribute("cardNum", deck.getCards().size()); | ||
req.setAttribute("action", "new"); | ||
req.setAttribute("create", true); | ||
|
||
return "deck/deck_creation"; | ||
} | ||
|
||
@GetMapping("/create/deck/{deckId}") | ||
public String getCreateFormWithDeck(@PathVariable("deckId") Integer deckId, HttpServletRequest req, | ||
HttpServletResponse res) { | ||
|
||
DeckModel deck = deckRepository.getById(deckId); | ||
|
||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); | ||
String loggedUsername = authentication.getName(); | ||
UserModel userModel = userRepository.findByUsername(loggedUsername); | ||
|
||
if (deck.getCreator().getId().equals(userModel.getId())) { | ||
req.setAttribute("deck", deck); | ||
req.setAttribute("cardNum", deck.getCards().size()); | ||
req.setAttribute("action", "edit"); | ||
req.setAttribute("create", true); | ||
return "deck/deck_creation"; | ||
} else { | ||
return redirectError; | ||
} | ||
|
||
} | ||
|
||
@PostMapping("/create/deck") | ||
public String saveDeckForFirstTime(HttpServletRequest req, HttpServletResponse res) { | ||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); | ||
String loggedUsername = authentication.getName(); | ||
UserModel loggedUser = userRepository.findByUsername(loggedUsername); | ||
|
||
DeckModel deck = new DeckModel(); | ||
|
||
deck.setCreator(loggedUser); | ||
deck = deckRepository.save(deck); | ||
|
||
deck.setTitle(req.getParameter("title")); | ||
deck.setDescription(req.getParameter("description")); | ||
deck.setImgPath("/images/deck/default.png"); | ||
|
||
String redirectUrl = "redirect:/create/deck/" + deck.getId(); | ||
String action = req.getParameter("action"); | ||
|
||
redirectUrl = deckCreationUtils.checkAction(req, res, deck, action); | ||
|
||
return redirectUrl; | ||
} | ||
|
||
@PostMapping("/create/deck/{deckId}") | ||
public String createDeck(@PathVariable("deckId") Integer deckId, HttpServletRequest req, | ||
HttpServletResponse res) { | ||
|
||
DeckModel deck = deckRepository.getById(deckId); | ||
deck.setTitle(req.getParameter("title")); | ||
deck.setDescription(req.getParameter("description")); | ||
deck.setImgPath("/images/deck/default.png"); | ||
|
||
String redirectUrl = "redirect:/create/deck/" + deck.getId(); | ||
String action = req.getParameter("action"); | ||
|
||
redirectUrl = deckCreationUtils.checkAction(req, res, deck, action); | ||
|
||
return redirectUrl; | ||
} | ||
} |
Oops, something went wrong.