This repository was archived by the owner on Jun 3, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
Add feed page that displays recipes pertaining to users' followed tags. #89
Open
nonsensicle
wants to merge
7
commits into
master
Choose a base branch
from
CustomFeed
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
4cb539d
Add feed page that displays recipes pertaining to users' followed tag…
nonsensicle bcce358
Fix formatting errors
nonsensicle ffc4a03
Update sidebar
nonsensicle b6a2ee5
Merge master.
nonsensicle 449f629
Add sorting method to followed tags feed; update getRecipeList() in R…
nonsensicle a16e87f
Finished react with sort for followed tags page.
nonsensicle d93ebd7
adding array of tagIDs to recipeMetadata class in order to query more…
nonsensicle File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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 hidden or 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,6 +1,7 @@ | ||
| package com.google.sps.meltingpot.data; | ||
|
|
||
| import com.google.api.core.ApiFuture; | ||
| import com.google.cloud.firestore.CollectionReference; | ||
| import com.google.cloud.firestore.DocumentReference; | ||
| import com.google.cloud.firestore.DocumentSnapshot; | ||
| import com.google.cloud.firestore.FieldValue; | ||
|
|
@@ -9,11 +10,14 @@ | |
| import com.google.cloud.firestore.Transaction; | ||
| import com.google.cloud.firestore.WriteBatch; | ||
| import java.util.ArrayList; | ||
| import java.util.Calendar; | ||
| import java.util.Collections; | ||
| import java.util.Comparator; | ||
| import java.util.HashSet; | ||
| import java.util.Iterator; | ||
| import java.util.List; | ||
| import java.util.Map; | ||
| import java.util.Set; | ||
|
|
||
| public class FirestoreDB implements DBInterface { | ||
| private static final int RECIPES_PER_PAGE = 12; | ||
|
|
@@ -251,6 +255,61 @@ public List<RecipeMetadata> getRecipesMatchingCreator( | |
| return getRecipeMetadataQuery(recipesQuery, sortingMethod); | ||
| } | ||
|
|
||
| // TODO: Currently, sorting method is unused. Used TOP in recipesMatchingAnyTags() for consistent | ||
| // order. | ||
| public List<RecipeMetadata> getRecipesMatchingFollowedTags( | ||
| String userId, SortingMethod sortingMethod, int page) { | ||
| List<RecipeMetadata> followedTagsRecipes = recipesMatchingAnyTags(followedTagIds(userId)); | ||
|
|
||
| // Sort the results. | ||
| switch (sortingMethod) { | ||
| case TOP: | ||
| Collections.sort(followedTagsRecipes, | ||
| Collections.reverseOrder(Comparator.comparingLong(RecipeMetadata::getVotes))); | ||
| break; | ||
| case NEW: | ||
| Collections.sort(followedTagsRecipes, | ||
| Collections.reverseOrder(Comparator.comparingLong(RecipeMetadata::getTimestamp))); | ||
| break; | ||
| } | ||
|
|
||
| // Return the appropriate page of recipes manually. | ||
| try { | ||
| return followedTagsRecipes.subList( | ||
| (page * RECIPES_PER_PAGE), ((page + 1) * RECIPES_PER_PAGE)); | ||
| } catch (IndexOutOfBoundsException e) { | ||
| if (page == 0) { | ||
| return followedTagsRecipes; | ||
| } else { | ||
| if (followedTagsRecipes.size() <= (page * RECIPES_PER_PAGE)) { | ||
| return null; | ||
| } else { | ||
| return ( | ||
| followedTagsRecipes.subList((page * RECIPES_PER_PAGE), followedTagsRecipes.size())); | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| public List<RecipeMetadata> getRecipesMatchingFollowedTags( | ||
| String userId, SortingMethod sortingMethod) { | ||
| List<RecipeMetadata> followedTagsRecipes = recipesMatchingAnyTags(followedTagIds(userId)); | ||
|
|
||
| // Sort the results. | ||
| switch (sortingMethod) { | ||
| case TOP: | ||
| Collections.sort(followedTagsRecipes, | ||
| Collections.reverseOrder(Comparator.comparingLong(RecipeMetadata::getVotes))); | ||
| break; | ||
| case NEW: | ||
| Collections.sort(followedTagsRecipes, | ||
| Collections.reverseOrder(Comparator.comparingLong(RecipeMetadata::getTimestamp))); | ||
| break; | ||
| } | ||
|
|
||
| return followedTagsRecipes; | ||
| } | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you want to do sorting, you could add some code like this (does sort on our end without firestore's help):
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here, getVotes and getTimestamp are simple getters I added on my branch |
||
|
|
||
| public List<RecipeMetadata> getRecipesSavedBy( | ||
| String userId, SortingMethod sortingMethod, int page) { | ||
| List<String> saved_Ids = savedRecipeIds(userId); | ||
|
|
@@ -289,6 +348,8 @@ private List<RecipeMetadata> getRecipeMetadataQuery( | |
| case NEW: | ||
| recipesQuery = recipesQuery.orderBy(Recipe.TIMESTAMP_KEY, Query.Direction.DESCENDING); | ||
| break; | ||
| case NONE: | ||
| break; | ||
| } | ||
|
|
||
| recipesQuery = recipesQuery.limit(MAX_RECIPES_PER_REQUEST); | ||
|
|
@@ -313,6 +374,8 @@ private List<RecipeMetadata> getRecipeMetadataQuery( | |
| case NEW: | ||
| recipesQuery = recipesQuery.orderBy(Recipe.TIMESTAMP_KEY, Query.Direction.DESCENDING); | ||
| break; | ||
| case NONE: | ||
| break; | ||
| } | ||
|
|
||
| recipesQuery = recipesQuery.offset(page * RECIPES_PER_PAGE).limit(RECIPES_PER_PAGE); | ||
|
|
@@ -334,6 +397,28 @@ public Query recipesMatchingTags(Iterable<String> tagIds, Iterator<String> iter) | |
| return DBUtils.recipeMetadata(); | ||
| } | ||
|
|
||
| // todo: add to interface (returns list of recipeIDs matching any of the tags) | ||
| public List<RecipeMetadata> recipesMatchingAnyTags(List<String> tagIds) { | ||
| CollectionReference recipes = DBUtils.recipeMetadata(); | ||
| Set<RecipeMetadata> metadata = new HashSet<RecipeMetadata>(); | ||
| // Testing out this line | ||
| List<RecipeMetadata> taggedRecipes = getRecipeMetadataQuery(recipes.whereArrayContainsAny("tagIdsArray", tagIds), SortingMethod.NONE); | ||
| //for (String tagId : tagIds) { | ||
| // Get only relevant recipes from the last week. | ||
| // Calendar calendar = Calendar.getInstance(); | ||
| // calendar.add(Calendar.WEEK_OF_YEAR, -1); | ||
| //long oneWeekAgo = | ||
| // calendar.getTime().getTime(); // in millis. Calendar.getTime() returns a Date. | ||
| // metadata.addAll( | ||
| // getRecipeMetadataQuery(recipes.whereEqualTo("tagIds." + tagId, true) | ||
| // .whereGreaterThanOrEqualTo("timestamp", oneWeekAgo), | ||
| // SortingMethod.NONE)); | ||
| // } | ||
| //List<RecipeMetadata> taggedRecipes = new ArrayList<RecipeMetadata>(metadata); | ||
| //taggedRecipes.addAll(metadata); | ||
| return taggedRecipes; | ||
| } | ||
|
|
||
| public List<String> savedRecipeIds(String userId) { | ||
| DocumentReference userRef = DBUtils.user(userId); | ||
| DocumentSnapshot user = DBUtils.blockOnFuture(userRef.get()); | ||
|
|
||
This file contains hidden or 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 hidden or 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 |
|---|---|---|
|
|
@@ -90,7 +90,8 @@ public void doPost(HttpServletRequest request, HttpServletResponse response) thr | |
| if (uid == null) { | ||
| return; | ||
| } | ||
|
|
||
|
|
||
| newRecipe.metadata.tagIdsArray = new ArrayList<String>(newRecipe.metadata.tagIds.keySet()); | ||
| newRecipe.metadata.creatorId = uid; | ||
| newRecipe.metadata.votes = 0; | ||
| newRecipe.metadata.timestamp = System.currentTimeMillis(); | ||
|
|
@@ -162,12 +163,25 @@ protected String getRecipeList(HttpServletRequest request, HttpServletResponse r | |
| } | ||
|
|
||
| String tagIDs[] = request.getParameterValues("tagIDs"); | ||
| // TODO: change sorting method tags to parameter tags | ||
| boolean isFollowedTagsRequest = Boolean.parseBoolean(request.getParameter("followed-tags")); | ||
| boolean isSavedRequest = Boolean.parseBoolean(request.getParameter("saved")); | ||
|
|
||
| boolean isTagQuery = (tagIDs != null && tagIDs.length > 0 && !tagIDs[0].equals("None")); | ||
| boolean isCreatorQuery = (creatorToken != null && !creatorToken.equals("None")); | ||
| boolean isFollowedTagsQuery = (isCreatorQuery && isFollowedTagsRequest); | ||
|
|
||
| if (isFollowedTagsQuery) { | ||
| // If the front end is requesting recipes tagged with the tags that a certain user follows, | ||
| // then perform that query | ||
| String uid = Auth.getUid(creatorToken, response); | ||
| if (uid == null) { | ||
| return null; | ||
| } | ||
|
|
||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What if the user wants to sort by new or top for their custom feed? I feel like we should have some other flag to determine whether it's a followedTagsQuery |
||
| if (isSavedRequest || (isCreatorQuery && !isTagQuery)) { | ||
| return gson.toJson(page != null ? db.getRecipesMatchingFollowedTags(uid, sortingMethod, page) | ||
| : db.getRecipesMatchingFollowedTags(uid, sortingMethod)); | ||
| } else if (isSavedRequest || (isCreatorQuery && !isTagQuery)) { | ||
| // If frontend is requesting saved recipes or created recipes of a given user, | ||
| // make sure they are authenticated | ||
| String uid = Auth.getUid(creatorToken, response); | ||
|
|
||
This file contains hidden or 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,33 @@ | ||
| import React from "react"; | ||
| import PropTypes from "prop-types"; | ||
| import Select from "react-select"; | ||
|
|
||
| const SortTypeSelect = props => { | ||
| const options = [ | ||
| { value: "NEW", label: "New" }, | ||
| { value: "TOP", label: "Top of last week" }, | ||
| ]; | ||
|
|
||
| return ( | ||
| <Select | ||
| id="sort-select" | ||
| name="sort-select" | ||
| isMulti | ||
| options={options} | ||
| onChange={selected => { | ||
| if (selected === null) { | ||
| props.setSortType("NONE"); | ||
| return; | ||
| } | ||
| props.setSortType(selected.value); | ||
| }} | ||
| /> | ||
| ); | ||
| }; | ||
|
|
||
| SortTypeSelect.propTypes = { | ||
| sortType: PropTypes.string, | ||
| setSortType: PropTypes.func, | ||
| }; | ||
|
|
||
| export default SortTypeSelect; |
This file contains hidden or 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 hidden or 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 hidden or 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 hidden or 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 hidden or 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,28 @@ | ||
| import React, { useState } from "react"; | ||
| import PropTypes from "prop-types"; | ||
| import { CCol, CRow } from "@coreui/react"; | ||
| import SortTypeSelect from "../components/SortTypeSelect"; | ||
| import Feed from "./Feed"; | ||
|
|
||
| const FeedWithSort = props => { | ||
| const [sort, setSort] = useState(null); | ||
|
|
||
| return ( | ||
| <> | ||
| <CRow> | ||
| <CCol> | ||
| <SortTypeSelect sortType={sort} setSortType={setSort} /> | ||
| </CCol> | ||
| </CRow> | ||
| <br></br> | ||
| <br></br> | ||
| <Feed feedType={props.feedType} sortType={sort} /> | ||
| </> | ||
| ); | ||
| }; | ||
|
|
||
| FeedWithSort.propTypes = { | ||
| feedType: PropTypes.string, | ||
| }; | ||
|
|
||
| export default FeedWithSort; |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wouldn't you get this exception when you try to get the last page?