use of ai.elimu.model.contributor.Contributor in project webapp by elimu-ai.
the class SignOnControllerWeb3 method handleAuthorization.
/**
* Verify that an Ethereum signature was signed by a given Ethereum account. If true, we
* proceed with the sign-on process. Otherwise, we return an error message.
*/
@RequestMapping(value = "/sign-on/web3", method = RequestMethod.POST, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public String handleAuthorization(HttpServletRequest request, HttpSession session, @RequestParam String address, @RequestParam String signature) throws IOException {
logger.info("handleAuthorization");
logger.info("address: " + address);
if (StringUtils.isBlank(address)) {
return "redirect:/sign-on/web3?error=Missing address";
}
logger.info("signature: " + signature);
if (StringUtils.isBlank(signature)) {
return "redirect:/sign-on/web3?error=Missing signature";
}
// Check if the signature is valid
if (!isSignatureValid(address, signature, SIGNATURE_MESSAGE)) {
logger.warn("Invalid signature");
return "redirect:/sign-on/web3?error=Invalid signature";
}
logger.info("Valid signature ✍️");
// Check if the Contributor is currently signed on (via Google/GitHub)
Contributor authenticatedContributor = (Contributor) session.getAttribute("contributor");
logger.info("authenticatedContributor: " + authenticatedContributor);
if ((authenticatedContributor != null) && (authenticatedContributor.getId() != null)) {
// Check if a Contributor with this ETH address already exists in the database.
// If so, merge the two Contributors into one.
// TODO
// Update Web3 details of existing Contributor
authenticatedContributor.setProviderIdWeb3(address);
contributorDao.update(authenticatedContributor);
return "redirect:/content";
}
Contributor contributor = new Contributor();
contributor.setProviderIdWeb3(address);
// Check if a Contributor with this ETH address already exists in the database
Contributor existingContributor = contributorDao.readByProviderIdWeb3(address);
logger.info("existingContributor: " + existingContributor);
if (existingContributor == null) {
// Store new Contributor in database
contributor.setRegistrationTime(Calendar.getInstance());
contributor.setRoles(new HashSet<>(Arrays.asList(Role.CONTRIBUTOR)));
if (contributor.getEmail() == null) {
// Ask the Contributor to add her e-mail manually
request.getSession().setAttribute("contributor", contributor);
new CustomAuthenticationManager().authenticateUser(contributor);
return "redirect:/content/contributor/add-email";
}
contributorDao.create(contributor);
logger.info("Contributor " + contributor.getEmail() + " was created at " + request.getServerName());
} else {
contributor = existingContributor;
}
// Authenticate
new CustomAuthenticationManager().authenticateUser(contributor);
// Add Contributor object to session
request.getSession().setAttribute("contributor", contributor);
return "redirect:/content";
}
use of ai.elimu.model.contributor.Contributor in project webapp by elimu-ai.
the class DbContentImportHelper method performDatabaseContentImport.
/**
* Extracts educational content from the CSV files in {@code src/main/resources/db/content_TEST/<Language>/} and
* stores it in the database.
*
* @param environment The environment from which to import the database content.
* @param language The language to use during the import.
* @param webApplicationContext Context needed to access DAOs.
*/
public synchronized void performDatabaseContentImport(Environment environment, Language language, WebApplicationContext webApplicationContext) {
logger.info("performDatabaseContentImport");
logger.info("environment: " + environment + ", language: " + language);
if (!((environment == Environment.TEST) || (environment == Environment.PROD))) {
throw new IllegalArgumentException("Database content can only be imported from the TEST environment or from the PROD environment");
}
String contentDirectoryPath = "db" + File.separator + "content_" + environment + File.separator + language.toString().toLowerCase();
logger.info("contentDirectoryPath: \"" + contentDirectoryPath + "\"");
URL contentDirectoryURL = getClass().getClassLoader().getResource(contentDirectoryPath);
logger.info("contentDirectoryURL: " + contentDirectoryURL);
if (contentDirectoryURL == null) {
logger.warn("The content directory was not found. Aborting content import.");
return;
}
File contentDirectory = new File(contentDirectoryURL.getPath());
logger.info("contentDirectory: " + contentDirectory);
contributorDao = (ContributorDao) webApplicationContext.getBean("contributorDao");
Contributor contributor = new Contributor();
contributor.setEmail("dev@elimu.ai");
contributor.setFirstName("Dev");
contributor.setLastName("Contributor");
contributor.setRoles(new HashSet<>(Arrays.asList(Role.CONTRIBUTOR, Role.EDITOR, Role.ANALYST, Role.ADMIN)));
contributor.setRegistrationTime(Calendar.getInstance());
contributorDao.create(contributor);
// Extract and import Letters from CSV file in src/main/resources/
File lettersCsvFile = new File(contentDirectory, "letters.csv");
List<Letter> letters = CsvContentExtractionHelper.getLettersFromCsvBackup(lettersCsvFile, soundDao);
logger.info("letters.size(): " + letters.size());
letterDao = (LetterDao) webApplicationContext.getBean("letterDao");
letterContributionEventDao = (LetterContributionEventDao) webApplicationContext.getBean("letterContributionEventDao");
for (Letter letter : letters) {
letterDao.create(letter);
LetterContributionEvent letterContributionEvent = new LetterContributionEvent();
letterContributionEvent.setContributor(contributor);
letterContributionEvent.setLetter(letter);
letterContributionEvent.setRevisionNumber(1);
letterContributionEvent.setTime(Calendar.getInstance());
letterContributionEvent.setTimeSpentMs((long) (Math.random() * 10) * 60000L);
letterContributionEvent.setPlatform(Platform.WEBAPP);
letterContributionEventDao.create(letterContributionEvent);
}
// Extract and import Sounds from CSV file in src/main/resources/
File soundsCsvFile = new File(contentDirectory, "sounds.csv");
List<Sound> sounds = CsvContentExtractionHelper.getSoundsFromCsvBackup(soundsCsvFile);
logger.info("sounds.size(): " + sounds.size());
soundDao = (SoundDao) webApplicationContext.getBean("soundDao");
for (Sound sound : sounds) {
soundDao.create(sound);
}
// Extract and import letter-sound correspondences in src/main/resources/
File letterToAllophioneMappingsCsvFile = new File(contentDirectory, "letter-sound-correspondences.csv");
List<LetterSoundCorrespondence> letterSoundCorrespondences = CsvContentExtractionHelper.getLetterSoundCorrespondencesFromCsvBackup(letterToAllophioneMappingsCsvFile, letterDao, soundDao, letterSoundCorrespondenceDao);
logger.info("letterSoundCorrespondences.size(): " + letterSoundCorrespondences.size());
letterSoundCorrespondenceDao = (LetterSoundCorrespondenceDao) webApplicationContext.getBean("letterSoundCorrespondenceDao");
letterSoundCorrespondenceContributionEventDao = (LetterSoundCorrespondenceContributionEventDao) webApplicationContext.getBean("letterSoundCorrespondenceContributionEventDao");
for (LetterSoundCorrespondence letterSoundCorrespondence : letterSoundCorrespondences) {
letterSoundCorrespondenceDao.create(letterSoundCorrespondence);
LetterSoundCorrespondenceContributionEvent letterSoundCorrespondenceContributionEvent = new LetterSoundCorrespondenceContributionEvent();
letterSoundCorrespondenceContributionEvent.setContributor(contributor);
letterSoundCorrespondenceContributionEvent.setLetterSoundCorrespondence(letterSoundCorrespondence);
letterSoundCorrespondenceContributionEvent.setRevisionNumber(1);
letterSoundCorrespondenceContributionEvent.setTime(Calendar.getInstance());
letterSoundCorrespondenceContributionEvent.setTimeSpentMs((long) (Math.random() * 10) * 60000L);
letterSoundCorrespondenceContributionEvent.setPlatform(Platform.WEBAPP);
letterSoundCorrespondenceContributionEventDao.create(letterSoundCorrespondenceContributionEvent);
}
// Extract and import Words from CSV file in src/main/resources/
File wordsCsvFile = new File(contentDirectory, "words.csv");
List<Word> words = CsvContentExtractionHelper.getWordsFromCsvBackup(wordsCsvFile, letterDao, soundDao, letterSoundCorrespondenceDao, wordDao);
logger.info("words.size(): " + words.size());
wordDao = (WordDao) webApplicationContext.getBean("wordDao");
wordContributionEventDao = (WordContributionEventDao) webApplicationContext.getBean("wordContributionEventDao");
for (Word word : words) {
wordDao.create(word);
WordContributionEvent wordContributionEvent = new WordContributionEvent();
wordContributionEvent.setContributor(contributor);
wordContributionEvent.setWord(word);
wordContributionEvent.setRevisionNumber(1);
wordContributionEvent.setTime(Calendar.getInstance());
wordContributionEvent.setTimeSpentMs((long) (Math.random() * 10) * 60000L);
wordContributionEvent.setPlatform(Platform.WEBAPP);
wordContributionEventDao.create(wordContributionEvent);
}
// Extract and import Numbers from CSV file in src/main/resources/
File numbersCsvFile = new File(contentDirectory, "numbers.csv");
List<Number> numbers = CsvContentExtractionHelper.getNumbersFromCsvBackup(numbersCsvFile, wordDao);
logger.info("numbers.size(): " + numbers.size());
numberDao = (NumberDao) webApplicationContext.getBean("numberDao");
numberContributionEventDao = (NumberContributionEventDao) webApplicationContext.getBean("numberContributionEventDao");
for (Number number : numbers) {
numberDao.create(number);
NumberContributionEvent numberContributionEvent = new NumberContributionEvent();
numberContributionEvent.setContributor(contributor);
numberContributionEvent.setNumber(number);
numberContributionEvent.setRevisionNumber(1);
numberContributionEvent.setTime(Calendar.getInstance());
numberContributionEvent.setTimeSpentMs((long) (Math.random() * 10) * 60000L);
numberContributionEvent.setPlatform(Platform.WEBAPP);
numberContributionEventDao.create(numberContributionEvent);
}
// Extract and import Syllables from CSV file in src/main/resources/
// TODO
// Extract and import Emojis from CSV file in src/main/resources/
File emojisCsvFile = new File(contentDirectory, "emojis.csv");
List<Emoji> emojis = CsvContentExtractionHelper.getEmojisFromCsvBackup(emojisCsvFile, wordDao);
logger.info("emojis.size(): " + emojis.size());
emojiDao = (EmojiDao) webApplicationContext.getBean("emojiDao");
for (Emoji emoji : emojis) {
emojiDao.create(emoji);
}
// Extract and import Images from CSV file in src/main/resources/
// TODO
// Extract and import Audios from CSV file in src/main/resources/
// TODO
// Extract and import StoryBooks from CSV file in src/main/resources/
File storyBooksCsvFile = new File(contentDirectory, "storybooks.csv");
List<StoryBookGson> storyBookGsons = CsvContentExtractionHelper.getStoryBooksFromCsvBackup(storyBooksCsvFile);
logger.info("storyBookGsons.size(): " + storyBookGsons.size());
storyBookDao = (StoryBookDao) webApplicationContext.getBean("storyBookDao");
storyBookChapterDao = (StoryBookChapterDao) webApplicationContext.getBean("storyBookChapterDao");
storyBookParagraphDao = (StoryBookParagraphDao) webApplicationContext.getBean("storyBookParagraphDao");
storyBookContributionEventDao = (StoryBookContributionEventDao) webApplicationContext.getBean("storyBookContributionEventDao");
for (StoryBookGson storyBookGson : storyBookGsons) {
// Convert from GSON to JPA
StoryBook storyBook = new StoryBook();
storyBook.setTitle(storyBookGson.getTitle());
storyBook.setDescription(storyBookGson.getDescription());
// TODO: storyBook.setContentLicense();
// TODO: storyBook.setAttributionUrl();
storyBook.setReadingLevel(storyBookGson.getReadingLevel());
storyBookDao.create(storyBook);
for (StoryBookChapterGson storyBookChapterGson : storyBookGson.getStoryBookChapters()) {
// Convert from GSON to JPA
StoryBookChapter storyBookChapter = new StoryBookChapter();
storyBookChapter.setStoryBook(storyBook);
storyBookChapter.setSortOrder(storyBookChapterGson.getSortOrder());
// TODO: storyBookChapter.setImage();
storyBookChapterDao.create(storyBookChapter);
for (StoryBookParagraphGson storyBookParagraphGson : storyBookChapterGson.getStoryBookParagraphs()) {
// Convert from GSON to JPA
StoryBookParagraph storyBookParagraph = new StoryBookParagraph();
storyBookParagraph.setStoryBookChapter(storyBookChapter);
storyBookParagraph.setSortOrder(storyBookParagraphGson.getSortOrder());
storyBookParagraph.setOriginalText(storyBookParagraphGson.getOriginalText());
List<String> wordsInOriginalText = WordExtractionHelper.getWords(storyBookParagraph.getOriginalText(), language);
logger.info("wordsInOriginalText.size(): " + wordsInOriginalText.size());
List<Word> paragraphWords = new ArrayList<>();
logger.info("paragraphWords.size(): " + paragraphWords.size());
for (String wordInOriginalText : wordsInOriginalText) {
logger.info("wordInOriginalText: \"" + wordInOriginalText + "\"");
wordInOriginalText = wordInOriginalText.toLowerCase();
logger.info("wordInOriginalText (lower-case): \"" + wordInOriginalText + "\"");
Word word = wordDao.readByText(wordInOriginalText);
logger.info("word: " + word);
paragraphWords.add(word);
}
storyBookParagraph.setWords(paragraphWords);
storyBookParagraphDao.create(storyBookParagraph);
}
}
StoryBookContributionEvent storyBookContributionEvent = new StoryBookContributionEvent();
storyBookContributionEvent.setContributor(contributor);
storyBookContributionEvent.setStoryBook(storyBook);
storyBookContributionEvent.setRevisionNumber(1);
storyBookContributionEvent.setTime(Calendar.getInstance());
storyBookContributionEvent.setTimeSpentMs((long) (Math.random() * 10) * 60000L);
storyBookContributionEvent.setPlatform(Platform.WEBAPP);
storyBookContributionEventDao.create(storyBookContributionEvent);
}
// Extract and import Videos from CSV file in src/main/resources/
// TODO
String analyticsDirectoryPath = "db" + File.separator + "analytics_" + environment + File.separator + language.toString().toLowerCase();
logger.info("analyticsDirectoryPath: \"" + analyticsDirectoryPath + "\"");
URL analyticsDirectoryURL = getClass().getClassLoader().getResource(analyticsDirectoryPath);
logger.info("analyticsDirectoryURL: " + analyticsDirectoryURL);
if (analyticsDirectoryURL == null) {
logger.warn("The analytics directory was not found. Aborting analytics import.");
return;
}
File analyticsDirectory = new File(analyticsDirectoryURL.getPath());
logger.info("analyticsDirectory: " + analyticsDirectory);
// Extract and import LetterLearningEvents from CSV file in src/main/resources/
// TODO
// Extract and import WordLearningEvents from CSV file in src/main/resources/
// TODO
// Extract and import StoryBookLearningEvents from CSV file in src/main/resources/
File storyBookLearningEventsCsvFile = new File(analyticsDirectory, "storybook-learning-events.csv");
applicationDao = (ApplicationDao) webApplicationContext.getBean("applicationDao");
List<StoryBookLearningEvent> storyBookLearningEvents = CsvAnalyticsExtractionHelper.getStoryBookLearningEventsFromCsvBackup(storyBookLearningEventsCsvFile, applicationDao, storyBookDao);
logger.info("storyBookLearningEvents.size(): " + storyBookLearningEvents.size());
storyBookLearningEventDao = (StoryBookLearningEventDao) webApplicationContext.getBean("storyBookLearningEventDao");
for (StoryBookLearningEvent storyBookLearningEvent : storyBookLearningEvents) {
storyBookLearningEventDao.create(storyBookLearningEvent);
}
logger.info("Content import complete");
}
use of ai.elimu.model.contributor.Contributor in project webapp by elimu-ai.
the class LetterSoundCorrespondencePeerReviewsController method handleGetRequest.
/**
* Get {@link LetterSoundCorrespondenceContributionEvent}s pending a {@link LetterSoundCorrespondencePeerReviewEvent} for the current {@link Contributor}.
*/
@RequestMapping(method = RequestMethod.GET)
public String handleGetRequest(HttpSession session, Model model) {
logger.info("handleGetRequest");
Contributor contributor = (Contributor) session.getAttribute("contributor");
logger.info("contributor: " + contributor);
// Get the most recent LetterSoundCorrespondenceContributionEvent for each LetterSoundCorrespondence, including those made by the current Contributor
List<LetterSoundCorrespondenceContributionEvent> mostRecentLetterSoundCorrespondenceContributionEvents = letterSoundCorrespondenceContributionEventDao.readMostRecentPerLetterSoundCorrespondence();
logger.info("mostRecentLetterSoundCorrespondenceContributionEvents.size(): " + mostRecentLetterSoundCorrespondenceContributionEvents.size());
// For each LetterSoundCorrespondenceContributionEvent, check if the Contributor has already performed a peer-review.
// If not, add it to the list of pending peer reviews.
List<LetterSoundCorrespondenceContributionEvent> letterSoundCorrespondenceContributionEventsPendingPeerReview = new ArrayList<>();
for (LetterSoundCorrespondenceContributionEvent mostRecentLetterSoundCorrespondenceContributionEvent : mostRecentLetterSoundCorrespondenceContributionEvents) {
// Ignore LetterSoundCorrespondenceContributionEvents made by the current Contributor
if (mostRecentLetterSoundCorrespondenceContributionEvent.getContributor().getId().equals(contributor.getId())) {
continue;
}
// Check if the current Contributor has already peer-reviewed this LetterSoundCorrespondence contribution
List<LetterSoundCorrespondencePeerReviewEvent> letterSoundCorrespondencePeerReviewEvents = letterSoundCorrespondencePeerReviewEventDao.readAll(mostRecentLetterSoundCorrespondenceContributionEvent, contributor);
if (letterSoundCorrespondencePeerReviewEvents.isEmpty()) {
letterSoundCorrespondenceContributionEventsPendingPeerReview.add(mostRecentLetterSoundCorrespondenceContributionEvent);
}
}
logger.info("letterSoundCorrespondenceContributionEventsPendingPeerReview.size(): " + letterSoundCorrespondenceContributionEventsPendingPeerReview.size());
model.addAttribute("letterSoundCorrespondenceContributionEventsPendingPeerReview", letterSoundCorrespondenceContributionEventsPendingPeerReview);
return "content/letter-sound-correspondence/peer-reviews/pending";
}
use of ai.elimu.model.contributor.Contributor in project webapp by elimu-ai.
the class SignOnControllerGitHub method handleCallback.
@RequestMapping(value = "/sign-on/github/callback", method = RequestMethod.GET)
public String handleCallback(HttpServletRequest request, Model model) {
logger.info("handleCallback");
String state = request.getParameter("state");
logger.debug("state: " + state);
if (!secretState.equals(state)) {
return "redirect:/sign-on?error=state_mismatch";
} else {
String code = request.getParameter("code");
logger.debug("verifierParam: " + code);
String responseBody = null;
logger.info("Trading the Authorization Code for an Access Token...");
try {
OAuth2AccessToken accessToken = oAuth20Service.getAccessToken(code);
logger.debug("accessToken: " + accessToken);
logger.info("Got the Access Token!");
// Access the protected resource
OAuthRequest oAuthRequest = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL);
oAuth20Service.signRequest(accessToken, oAuthRequest);
Response response = oAuth20Service.execute(oAuthRequest);
responseBody = response.getBody();
logger.info("response.getCode(): " + response.getCode());
logger.info("response.getBody(): " + responseBody);
} catch (IOException | InterruptedException | ExecutionException ex) {
logger.error(ex);
return "redirect:/sign-on?error=" + ex.getMessage();
}
JSONObject jsonObject = new JSONObject(responseBody);
logger.info("jsonObject: " + jsonObject);
Contributor contributor = new Contributor();
if (jsonObject.has("email") && !jsonObject.isNull("email")) {
contributor.setEmail(jsonObject.getString("email"));
}
if (jsonObject.has("login")) {
contributor.setUsernameGitHub(jsonObject.getString("login"));
}
if (jsonObject.has("id")) {
Long idAsLong = jsonObject.getLong("id");
String id = String.valueOf(idAsLong);
contributor.setProviderIdGitHub(id);
}
if (jsonObject.has("avatar_url")) {
contributor.setImageUrl(jsonObject.getString("avatar_url"));
}
if (jsonObject.has("name") && !jsonObject.isNull("name")) {
String name = jsonObject.getString("name");
String[] nameParts = name.split(" ");
String firstName = nameParts[0];
logger.info("firstName: " + firstName);
contributor.setFirstName(firstName);
if (nameParts.length > 1) {
String lastName = nameParts[nameParts.length - 1];
logger.info("lastName: " + lastName);
contributor.setLastName(lastName);
}
}
// Look for existing Contributor with matching e-mail address
Contributor existingContributor = contributorDao.read(contributor.getEmail());
if (existingContributor == null) {
// Look for existing Contributor with matching GitHub id
existingContributor = contributorDao.readByProviderIdGitHub(contributor.getProviderIdGitHub());
}
logger.info("existingContributor: " + existingContributor);
if (existingContributor == null) {
// Store new Contributor in database
contributor.setRegistrationTime(Calendar.getInstance());
contributor.setRoles(new HashSet<>(Arrays.asList(Role.CONTRIBUTOR)));
if (contributor.getEmail() == null) {
// Ask the Contributor to add her e-mail manually
request.getSession().setAttribute("contributor", contributor);
new CustomAuthenticationManager().authenticateUser(contributor);
return "redirect:/content/contributor/add-email";
}
contributorDao.create(contributor);
logger.info("Contributor " + contributor.getEmail() + " was created at " + request.getServerName());
} else {
// Update existing contributor with latest values fetched from provider
if (StringUtils.isNotBlank(contributor.getUsernameGitHub())) {
existingContributor.setUsernameGitHub(contributor.getUsernameGitHub());
}
if (StringUtils.isNotBlank(contributor.getProviderIdGitHub())) {
existingContributor.setProviderIdGitHub(contributor.getProviderIdGitHub());
}
if (StringUtils.isNotBlank(contributor.getImageUrl())) {
existingContributor.setImageUrl(contributor.getImageUrl());
}
if (StringUtils.isNotBlank(contributor.getFirstName())) {
existingContributor.setFirstName(contributor.getFirstName());
}
if (StringUtils.isNotBlank(contributor.getLastName())) {
existingContributor.setLastName(contributor.getLastName());
}
contributorDao.update(existingContributor);
contributor = existingContributor;
}
// Authenticate
new CustomAuthenticationManager().authenticateUser(contributor);
// Add Contributor object to session
request.getSession().setAttribute("contributor", contributor);
return "redirect:/content";
}
}
use of ai.elimu.model.contributor.Contributor in project webapp by elimu-ai.
the class EditMotivationController method handleSubmit.
@RequestMapping(method = RequestMethod.POST)
public String handleSubmit(HttpSession session, @RequestParam String motivation, Model model) {
logger.info("handleSubmit");
logger.info("motivation: " + motivation);
if (StringUtils.isBlank(motivation)) {
model.addAttribute("errorCode", "NotNull.motivation");
return "content/contributor/edit-motivation";
} else {
Contributor contributor = (Contributor) session.getAttribute("contributor");
if (StringUtils.isBlank(contributor.getMotivation())) {
// The Contributor completed the on-boarding wizard for the first time
String contentUrl = "http://" + EnvironmentContextLoaderListener.PROPERTIES.getProperty("content.language").toLowerCase() + ".elimu.ai/content/contributor/" + contributor.getId();
String embedThumbnailUrl = null;
if (StringUtils.isNotBlank(contributor.getImageUrl())) {
embedThumbnailUrl = contributor.getImageUrl();
}
DiscordHelper.sendChannelMessage("Contributor joined: " + contentUrl, contributor.getFirstName() + " " + contributor.getLastName(), "Motivation: \"" + motivation + "\"", null, embedThumbnailUrl);
}
contributor.setMotivation(motivation);
contributorDao.update(contributor);
session.setAttribute("contributor", contributor);
return "redirect:/content";
}
}
Aggregations