Skip to content

Commit

Permalink
Merge pull request #79 from nicholasangcx/cloudStorage
Browse files Browse the repository at this point in the history
[v1.3] Logging in to Dropbox
  • Loading branch information
nicholasangcx committed Mar 30, 2018
2 parents eadeace + 046538e commit 5ad816c
Show file tree
Hide file tree
Showing 19 changed files with 464 additions and 87 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//@@author nicholasangcx
package seedu.recipe.commons.events.ui;

import seedu.recipe.commons.events.BaseEvent;

/**
* Indicates a request to upload recipes to Dropbox
*/
public class UploadRecipesEvent extends BaseEvent {

private String xmlExtensionFilename;

public UploadRecipesEvent(String xmlExtensionFilename) {
this.xmlExtensionFilename = xmlExtensionFilename;
}

public String getUploadFilename() {
return this.xmlExtensionFilename;
}

@Override
public String toString() {
return this.getClass().getSimpleName();
}
}
//@@author
3 changes: 1 addition & 2 deletions src/main/java/seedu/recipe/logic/Logic.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import javafx.collections.ObservableList;
import seedu.recipe.logic.commands.CommandResult;
import seedu.recipe.logic.commands.exceptions.CommandException;
import seedu.recipe.logic.commands.exceptions.UploadCommandException;
import seedu.recipe.logic.parser.exceptions.ParseException;
import seedu.recipe.model.recipe.Recipe;

Expand All @@ -18,7 +17,7 @@ public interface Logic {
* @throws CommandException If an error occurs during command execution.
* @throws ParseException If an error occurs during parsing.
*/
CommandResult execute(String commandText) throws CommandException, ParseException, UploadCommandException;
CommandResult execute(String commandText) throws CommandException, ParseException;

/** Returns an unmodifiable view of the filtered list of recipes */
ObservableList<Recipe> getFilteredRecipeList();
Expand Down
3 changes: 1 addition & 2 deletions src/main/java/seedu/recipe/logic/LogicManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import seedu.recipe.logic.commands.Command;
import seedu.recipe.logic.commands.CommandResult;
import seedu.recipe.logic.commands.exceptions.CommandException;
import seedu.recipe.logic.commands.exceptions.UploadCommandException;
import seedu.recipe.logic.parser.RecipeBookParser;
import seedu.recipe.logic.parser.exceptions.ParseException;
import seedu.recipe.model.Model;
Expand All @@ -33,7 +32,7 @@ public LogicManager(Model model) {
}

@Override
public CommandResult execute(String commandText) throws CommandException, ParseException, UploadCommandException {
public CommandResult execute(String commandText) throws CommandException, ParseException {
logger.info("----------------[USER COMMAND][" + commandText + "]");
try {
Command command = recipeBookParser.parseCommand(commandText);
Expand Down
3 changes: 1 addition & 2 deletions src/main/java/seedu/recipe/logic/commands/Command.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import seedu.recipe.logic.CommandHistory;
import seedu.recipe.logic.UndoRedoStack;
import seedu.recipe.logic.commands.exceptions.CommandException;
import seedu.recipe.logic.commands.exceptions.UploadCommandException;
import seedu.recipe.model.Model;

/**
Expand Down Expand Up @@ -43,7 +42,7 @@ public static String getMessageForTagListShownSummary(int displaySize, String ta
* @return feedback message of the operation result for display
* @throws CommandException If an error occurs during command execution.
*/
public abstract CommandResult execute() throws CommandException, UploadCommandException;
public abstract CommandResult execute() throws CommandException;

/**
* Provides any needed dependencies to the command.
Expand Down
64 changes: 18 additions & 46 deletions src/main/java/seedu/recipe/logic/commands/UploadCommand.java
Original file line number Diff line number Diff line change
@@ -1,19 +1,13 @@
//@@author nicholasangcx
package seedu.recipe.logic.commands;

import static seedu.recipe.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
import static seedu.recipe.storage.model.Filename.MESSAGE_FILENAME_CONSTRAINTS;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

import com.dropbox.core.DbxException;
import com.dropbox.core.DbxRequestConfig;
import com.dropbox.core.v2.DbxClientV2;

import seedu.recipe.commons.util.FileUtil;
import seedu.recipe.logic.commands.exceptions.UploadCommandException;
import seedu.recipe.commons.core.EventsCenter;
import seedu.recipe.commons.core.index.Index;
import seedu.recipe.commons.events.ui.JumpToListRequestEvent;
import seedu.recipe.commons.events.ui.UploadRecipesEvent;
import seedu.recipe.ui.util.CloudStorageUtil;

/**
* Uploads all recipes online, specifically to Dropbox.
Expand All @@ -23,56 +17,34 @@ public class UploadCommand extends Command {
public static final String COMMAND_WORD = "upload";
public static final String MESSAGE_SUCCESS = "Upload success!";
public static final String MESSAGE_FAILURE = "Failed to upload!";
public static final String MESSAGE_UPLOAD = "Connecting to Dropbox......";

public static final String MESSAGE_USAGE = COMMAND_WORD + ": Uploads all recipes to your Dropbox with the "
+ "specified filename, with no spaces. It will only take in the first parameter. Filename cannot start "
+ "with blackslash or frontslash or have two slashes consecutively.\n"
+ "specified filename, with no spaces. It will only take in the first parameter. "
+ MESSAGE_FILENAME_CONSTRAINTS + "\n"
+ "Parameters: KEYWORD\n"
+ "Example: " + COMMAND_WORD + " RecipeBook";

private static final String ACCESS_TOKEN = "nF-Ym1zvMnAAAAAAAAAAPYd-4nRthqNAuk343dpYSiQXXHLBJFNraaaUUgPwokxl";
private static final String RECIPE_DATA_FOLDER = FileUtil.getPath("data/");
private static final File RECIPE_BOOK_FILE = new File(RECIPE_DATA_FOLDER + "recipebook.xml");
private static final String clientIdentifier = "dropbox/recirecipe";
private static final Index FIRST_INDEX = Index.fromOneBased(1);

private final String xmlExtensionFilename;
public final String xmlExtensionFilename;

/**
* Creates an UploadCommand to upload addressbook.xml to Dropbox with the
* Creates an UploadCommand to upload recipebook.xml to Dropbox with the
* specified {@code String XmlExtensionFilename}
*/
public UploadCommand(String xmlExtensionFilename) {
this.xmlExtensionFilename = xmlExtensionFilename;
}

@Override
public CommandResult execute() throws UploadCommandException {
CommandResult result = upload();
return result;
}

/**
* Creates a Dropbox client with the user's {@code ACCESS_TOKEN}
* and uploads file specified by {@code RECIPE_BOOK_FILE} to their Dropbox account
* @return {@code CommandResult}
* @throws DbxException
*/
private CommandResult upload() throws UploadCommandException {
// Create Dropbox client
DbxRequestConfig config = DbxRequestConfig.newBuilder(clientIdentifier).build();
DbxClientV2 client = new DbxClientV2(config, ACCESS_TOKEN);

// Upload "addressbook.xml" to Dropbox
try (InputStream in = new FileInputStream(RECIPE_BOOK_FILE)) {
client.files().uploadBuilder("/" + xmlExtensionFilename)
.withAutorename(true)
.uploadAndFinish(in);
} catch (IOException e) {
return new CommandResult(MESSAGE_FAILURE);
} catch (DbxException dbe) {
throw new UploadCommandException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, MESSAGE_USAGE));
public CommandResult execute() {
EventsCenter.getInstance().post(new UploadRecipesEvent(xmlExtensionFilename));
if (CloudStorageUtil.hasAccessToken()) {
EventsCenter.getInstance().post(new JumpToListRequestEvent(FIRST_INDEX));
return new CommandResult(MESSAGE_SUCCESS);
}
return new CommandResult(MESSAGE_SUCCESS);
return new CommandResult(MESSAGE_UPLOAD);
}

@Override
Expand Down

This file was deleted.

13 changes: 10 additions & 3 deletions src/main/java/seedu/recipe/logic/parser/ParserUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import seedu.recipe.model.recipe.Servings;
import seedu.recipe.model.recipe.Url;
import seedu.recipe.model.tag.Tag;
import seedu.recipe.storage.model.Filename;

/**
* Contains utility methods used for parsing strings in the various *Parser classes.
Expand Down Expand Up @@ -403,14 +404,20 @@ public static Set<Tag> parseTags(Collection<String> tags) throws IllegalValueExc
}
return tagSet;
}

//@@author nicholasangcx
/**
* Parses {@code String filename} into a {@code String XmlExtensionFilename}.
* A .xml extension will be added to the original filename.
*
* @throws IllegalValueException if the give {@code filename} is invalid.
*/
public static String parseFilename(String filename) {
String xmlExtensionFilename = filename + ".xml";
return xmlExtensionFilename;
public static String parseFilename(String filename) throws IllegalValueException {
requireNonNull(filename);
if (!Filename.isValidFilename(filename)) {
throw new IllegalValueException(Filename.MESSAGE_FILENAME_CONSTRAINTS);
}
return filename + ".xml";
}
//@@author
}
13 changes: 9 additions & 4 deletions src/main/java/seedu/recipe/logic/parser/UploadCommandParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import static seedu.recipe.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;

import seedu.recipe.commons.exceptions.IllegalValueException;
import seedu.recipe.logic.commands.UploadCommand;
import seedu.recipe.logic.parser.exceptions.ParseException;

Expand All @@ -14,6 +15,7 @@ public class UploadCommandParser implements Parser<UploadCommand> {
/**
* Parses the given {@code String} of arguments in the context of the UploadCommand
* and returns an UploadCommand object for execution.
*
* @throws ParseException if the user input does not conform the expected format
*/
public UploadCommand parse(String args) throws ParseException {
Expand All @@ -23,11 +25,14 @@ public UploadCommand parse(String args) throws ParseException {
if (filename.isEmpty()) {
throw new ParseException(
String.format(MESSAGE_INVALID_COMMAND_FORMAT, UploadCommand.MESSAGE_USAGE));

}
String xmlExtensionFilename = ParserUtil.parseFilename(filename);

return new UploadCommand(xmlExtensionFilename);
try {
String xmlExtensionFilename = ParserUtil.parseFilename(filename);
return new UploadCommand(xmlExtensionFilename);
} catch (IllegalValueException ive) {
throw new ParseException(
String.format(MESSAGE_INVALID_COMMAND_FORMAT, UploadCommand.MESSAGE_USAGE));
}
}
}
//@author
47 changes: 47 additions & 0 deletions src/main/java/seedu/recipe/storage/model/Filename.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package seedu.recipe.storage.model;

import static java.util.Objects.requireNonNull;
import static seedu.recipe.commons.util.AppUtil.checkArgument;

/**
* Represents a Filename used to upload to Dropbox
* Guarantees: immutable; filename is valid as declared in {@link #isValidFilename(String)}
*/
public class Filename {

public static final String MESSAGE_FILENAME_CONSTRAINTS = "Filenames should not contain any"
+ " incompatible characters";
public static final String FILENAME_VALIDATION_REGEX = "[^\\Q<>:/|.?\"\\*\\E\\s]+";

public final String filename;

/**
* Constructs a {@code Filename}
*
* @param filename a valid filename
*/
public Filename(String filename) {
requireNonNull(filename);
checkArgument(isValidFilename(filename), MESSAGE_FILENAME_CONSTRAINTS);
this.filename = filename;
}

/**
* Returns true if a given string is a valid filename.
*/
public static boolean isValidFilename(String test) {
return test.matches(FILENAME_VALIDATION_REGEX);
}

@Override
public boolean equals(Object other) {
return other == this // short circuit if same object
|| (other instanceof Filename // instanceof handles nulls
&& this.filename.equals(((Filename) other).filename)); // state check
}

@Override
public int hashCode() {
return filename.hashCode();
}
}
49 changes: 49 additions & 0 deletions src/main/java/seedu/recipe/ui/BrowserPanel.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,28 @@
import com.google.common.eventbus.Subscribe;

import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Worker;
import javafx.event.Event;
import javafx.fxml.FXML;
import javafx.scene.layout.Region;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import seedu.recipe.MainApp;
import seedu.recipe.commons.core.EventsCenter;
import seedu.recipe.commons.core.LogsCenter;
import seedu.recipe.commons.core.index.Index;
import seedu.recipe.commons.events.ui.InternetSearchRequestEvent;
import seedu.recipe.commons.events.ui.JumpToListRequestEvent;
import seedu.recipe.commons.events.ui.NewResultAvailableEvent;
import seedu.recipe.commons.events.ui.RecipePanelSelectionChangedEvent;
import seedu.recipe.commons.events.ui.ShareRecipeEvent;
import seedu.recipe.commons.events.ui.UploadRecipesEvent;
import seedu.recipe.logic.commands.UploadCommand;
import seedu.recipe.model.recipe.Recipe;
import seedu.recipe.model.recipe.Url;
import seedu.recipe.ui.util.CloudStorageUtil;
import seedu.recipe.ui.util.FacebookHandler;

/**
Expand All @@ -29,8 +40,10 @@ public class BrowserPanel extends UiPart<Region> {
public static final String SEARCH_PAGE_URL =
"https://se-edu.github.io/addressbook-level4/DummySearchPage.html?name=";
private static final String FXML = "BrowserPanel.fxml";
private static final Index FIRST_INDEX = Index.fromOneBased(1);

private Recipe recipeToShare;
private String uploadFilename;

private final Logger logger = LogsCenter.getLogger(this.getClass());

Expand All @@ -45,6 +58,8 @@ public BrowserPanel(boolean isDarkTheme) {

loadDefaultPage(isDarkTheme);
registerAsAnEventHandler(this);

setUpBrowserUrlListener();
}

public void loadPage(String url) {
Expand Down Expand Up @@ -105,5 +120,39 @@ private void handleShareRecipeEvent(ShareRecipeEvent event) {
loadPage(FacebookHandler.REDIRECT_DOMAIN);
}
}

/**
* Sets up a URL listener on the browser to watch for access token.
*/
private void setUpBrowserUrlListener() {
WebEngine browserEngine = browser.getEngine();
browserEngine.getLoadWorker().stateProperty().addListener(new ChangeListener<Worker.State>() {
@Override
public void changed(ObservableValue ov, Worker.State oldState, Worker.State newState) {
if (newState == Worker.State.SUCCEEDED) {
String url = browserEngine.getLocation();
System.out.println("passing by");
if (CloudStorageUtil.checkAndSetAccessToken(url)) {
CloudStorageUtil.upload(uploadFilename);
System.out.println("a");
EventsCenter.getInstance().post(new NewResultAvailableEvent(UploadCommand.MESSAGE_SUCCESS));
EventsCenter.getInstance().post(new JumpToListRequestEvent(FIRST_INDEX));
}
}
}
});
}
//@@author

//@@author nicholasangcx
@Subscribe
private void handleUploadRecipesEvent(UploadRecipesEvent event) {
loadPage(CloudStorageUtil.getAppropriateUrl());
System.out.println("1");
uploadFilename = event.getUploadFilename();
if (CloudStorageUtil.hasAccessToken()) {
CloudStorageUtil.upload(uploadFilename);
}
}
//@@author
}
Loading

0 comments on commit 5ad816c

Please sign in to comment.