import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
-import com.intellij.openapi.ui.DialogBuilder;
+import com.intellij.openapi.ui.DialogWrapper;
+import com.intellij.openapi.ui.InputValidatorEx;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.util.text.StringUtil;
import com.intellij.ui.DocumentAdapter;
import com.intellij.ui.components.JBScrollPane;
-import com.jetbrains.edu.learning.StudyPluginConfigurator;
+import com.jetbrains.edu.learning.StudyTwitterPluginConfigurator;
import com.jetbrains.edu.learning.StudyUtils;
+import com.jetbrains.edu.learning.courseFormat.Task;
+import org.apache.http.HttpStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import twitter4j.StatusUpdate;
import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
+import java.awt.*;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
public class StudyTwitterUtils {
private static final Logger LOG = Logger.getInstance(StudyTwitterUtils.class);
-
- /**
- * Configure twitter instance: authorize if needed or set access token and token secret provided by configurator.
- * @param twitter
- * @param project
- * @param isAuthorized
- * @throws TwitterException
- */
- public static void configureTwitter(@NotNull final Twitter twitter, @NotNull final Project project,
- final boolean isAuthorized) throws TwitterException {
- if (!isAuthorized) {
- authorize(project, twitter);
- }
- else {
- StudyPluginConfigurator configurator = StudyUtils.getConfigurator(project);
- if (configurator != null) {
- getTwitterForAuthorizedApp(twitter, configurator.getTwitterAccessToken(project), configurator.getTwitterTokenSecret(project));
- }
- }
- }
-
+
/**
* Set consumer key and secret.
- * @param consumerKey
- * @param consumerSecret
- * @return
+ * @return Twitter instance with consumer key and secret set.
*/
@NotNull
public static Twitter getTwitter(@NotNull final String consumerKey, @NotNull final String consumerSecret) {
/**
* Set access token and token secret in Twitter instance
- * @param twitter
- * @param accessToken
- * @param tokenSecret
*/
- private static void getTwitterForAuthorizedApp(Twitter twitter, @NotNull String accessToken,
- @NotNull String tokenSecret) {
+ private static void setAuthInfoInTwitter(Twitter twitter, @NotNull String accessToken,
+ @NotNull String tokenSecret) {
AccessToken token = new AccessToken(accessToken, tokenSecret);
twitter.setOAuthAccessToken(token);
}
- /**
- * Authorize user and save tokens by StudyPluginConfigurator#storeTwitterTokens
- * @param project
- * @param twitter
- * @throws TwitterException
- */
- public static void authorize(@NotNull final Project project, @NotNull final Twitter twitter) throws TwitterException {
- RequestToken requestToken = twitter.getOAuthRequestToken();
- BrowserUtil.browse(requestToken.getAuthorizationURL());
-
+ public static void createTwitterDialogAndShow(@NotNull Project project,
+ @NotNull final StudyTwitterPluginConfigurator configurator,
+ @NotNull Task task) {
ApplicationManager.getApplication().invokeLater(() -> {
- String pin = Messages.showInputDialog("Twitter PIN:", "Twitter Authorization", null, "", null);
- try {
- AccessToken token;
- if (pin != null && pin.length() > 0) {
- token = twitter.getOAuthAccessToken(requestToken, pin);
- }
- else {
- token = twitter.getOAuthAccessToken();
- }
- StudyPluginConfigurator configurator = StudyUtils.getConfigurator(project);
- if (configurator != null) {
- configurator.storeTwitterTokens(project, token.getToken(), token.getTokenSecret());
+ DialogWrapper.DoNotAskOption doNotAskOption = createDoNotAskOption(project, configurator);
+ StudyTwitterUtils.TwitterDialogPanel panel = configurator.getTweetDialogPanel(task);
+ if (panel != null) {
+ TwitterDialogWrapper wrapper = new TwitterDialogWrapper(project, panel, doNotAskOption);
+ wrapper.setDoNotAskOption(doNotAskOption);
+ panel.addTextFieldVerifier(createTextFieldLengthDocumentListener(wrapper, panel));
+
+ if (wrapper.showAndGet()) {
+ try {
+ boolean isAuthorized = !configurator.getTwitterAccessToken(project).isEmpty();
+ Twitter twitter = getTwitter(configurator.getConsumerKey(project), configurator.getConsumerSecret(project));
+ if (!isAuthorized) {
+ authorizeAndUpdateStatus(project, twitter, panel);
+ }
+ else {
+ setAuthInfoInTwitter(twitter, configurator.getTwitterAccessToken(project), configurator.getTwitterTokenSecret(project));
+ updateStatus(panel, twitter);
+ }
+ }
+ catch (TwitterException | IOException e) {
+ LOG.warn(e.getMessage());
+ Messages.showErrorDialog("Status wasn\'t updated. Please, check internet connection and try again", "Twitter");
+ }
}
else {
- LOG.warn("Plugin configurator not found");
+ LOG.warn("Panel is null");
}
}
- catch (TwitterException e) {
- if (401 == e.getStatusCode()) {
- LOG.warn("Unable to get the access token.");
- }
- else {
- LOG.warn(e.getMessage());
+ });
+ }
+
+
+ private static DialogWrapper.DoNotAskOption createDoNotAskOption(@NotNull final Project project,
+ @NotNull final StudyTwitterPluginConfigurator configurator) {
+ return new DialogWrapper.DoNotAskOption() {
+ @Override
+ public boolean isToBeShown() {
+ return true;
+ }
+
+ @Override
+ public void setToBeShown(boolean toBeShown, int exitCode) {
+ if (exitCode == DialogWrapper.CANCEL_EXIT_CODE || exitCode == DialogWrapper.OK_EXIT_CODE) {
+ configurator.setAskToTweet(project, toBeShown);
}
}
- });
+
+ @Override
+ public boolean canBeHidden() {
+ return true;
+ }
+
+ @Override
+ public boolean shouldSaveOptionsOnCancel() {
+ return true;
+ }
+
+ @NotNull
+ @Override
+ public String getDoNotShowMessage() {
+ return "Never ask me to tweet";
+ }
+ };
+ }
+
+ /**
+ * Post on twitter media and text from panel
+ * @param panel shown to user and used to provide data to post
+ */
+ public static void updateStatus(StudyTwitterUtils.TwitterDialogPanel panel, Twitter twitter) throws IOException, TwitterException {
+ StatusUpdate update = new StatusUpdate(panel.getMessage());
+ InputStream e = panel.getMediaSource();
+ if (e != null) {
+ File imageFile = FileUtil.createTempFile("twitter_media", panel.getMediaExtension());
+ FileUtil.copy(e, new FileOutputStream(imageFile));
+ update.media(imageFile);
+ }
+
+ twitter.updateStatus(update);
+ BrowserUtil.browse("https://twitter.com/");
}
/**
* Show twitter dialog, asking user to tweet about his achievements. Post tweet with provided by panel
* media and text.
* As a result of succeeded tweet twitter website is opened in default browser.
- * @param twitter
- * @param twitterDialogPanel
*/
- public static void showPostTweetDialogAndPostTweet(@NotNull Twitter twitter, @NotNull final TwitterDialogPanel twitterDialogPanel) {
+ public static void authorizeAndUpdateStatus(@NotNull final Project project, @NotNull final Twitter twitter,
+ @NotNull final StudyTwitterUtils.TwitterDialogPanel panel) throws TwitterException {
+ RequestToken requestToken = twitter.getOAuthRequestToken();
+ BrowserUtil.browse(requestToken.getAuthorizationURL());
+
ApplicationManager.getApplication().invokeLater(() -> {
- DialogBuilder builder = new DialogBuilder();
- twitterDialogPanel.addTextFieldVerifier(createTextFieldLengthDocumentListener(builder, twitterDialogPanel));
- builder.title("Twitter");
- builder.addOkAction().setText("Tweet");
- builder.addCancelAction();
- builder.setCenterPanel(new JBScrollPane(twitterDialogPanel));
- builder.resizable(true);
- if (builder.showAndGet()) {
- StatusUpdate update = new StatusUpdate(twitterDialogPanel.getMessage());
+ String pin = createAndShowPinDialog();
+ if (pin != null) {
try {
- InputStream inputStream = twitterDialogPanel.getMediaSource();
- if (inputStream != null) {
- File imageFile = FileUtil.createTempFile("twitter_media", "gif");
-
- FileUtil.copy(inputStream, new FileOutputStream(imageFile));
- update.media(imageFile);
+ AccessToken token = twitter.getOAuthAccessToken(requestToken, pin);
+ StudyTwitterPluginConfigurator configurator = StudyUtils.getTwitterConfigurator(project);
+ if (configurator != null) {
+ configurator.storeTwitterTokens(project, token.getToken(), token.getTokenSecret());
+ updateStatus(panel, twitter);
+ }
+ else {
+ LOG.warn("No twitter configurator is provided for the plugin");
}
- twitter.updateStatus(update);
- BrowserUtil.browse("https://twitter.com/");
}
- catch (IOException | TwitterException e) {
+ catch (TwitterException e) {
+ if (e.getStatusCode() == HttpStatus.SC_UNAUTHORIZED) {
+ LOG.warn("Unable to get the access token.");
+ LOG.warn(e.getMessage());
+ }
+ }
+ catch (IOException e) {
LOG.warn(e.getMessage());
- Messages.showErrorDialog("Status wasn't updated. Please, check internet connection and try again", "Twitter");
}
}
});
}
+ public static String createAndShowPinDialog() {
+ return Messages.showInputDialog("Twitter PIN:", "Twitter Authorization", null, "", new InputValidatorEx() {
+ @Nullable
+ @Override
+ public String getErrorText(String inputString) {
+ inputString = inputString.trim();
+ if (inputString.isEmpty()) {
+ return "PIN shouldn't be empty.";
+ }
+ if (!isNumeric(inputString)) {
+ return "PIN should be numeric.";
+ }
+ return null;
+ }
+
+ @Override
+ public boolean checkInput(String inputString) {
+ return getErrorText(inputString) == null;
+ }
+
+ @Override
+ public boolean canClose(String inputString) {
+ return true;
+ }
+
+ private boolean isNumeric(@NotNull final String string) {
+ for (char c: string.toCharArray()) {
+ if (!StringUtil.isDecimalDigit(c)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ });
+ }
+
/**
* Listener updates label indicating remaining symbols number like in twitter.
- * @param builder
- * @param panel
- * @return
*/
- public static DocumentListener createTextFieldLengthDocumentListener(@NotNull DialogBuilder builder, @NotNull final TwitterDialogPanel panel) {
+ private static DocumentListener createTextFieldLengthDocumentListener(@NotNull TwitterDialogWrapper builder, @NotNull final StudyTwitterUtils.TwitterDialogPanel panel) {
return new DocumentAdapter() {
@Override
protected void textChanged(DocumentEvent e) {
int length = e.getDocument().getLength();
if (length > 140 || length == 0) {
- builder.setOkActionEnabled(false);
+ builder.setOKActionEnabled(false);
panel.getRemainSymbolsLabel().setText("<html><font color='red'>" + String.valueOf(140 - length) + "</font></html>");
- }
- else {
- builder.setOkActionEnabled(true);
+ } else {
+ builder.setOKActionEnabled(true);
panel.getRemainSymbolsLabel().setText(String.valueOf(140 - length));
}
-
+
}
};
}
+ /**
+ * Dialog wrapper class with DoNotAsl option for asking user to tweet.
+ * */
+ private static class TwitterDialogWrapper extends DialogWrapper {
+ private StudyTwitterUtils.TwitterDialogPanel myPanel;
+
+ TwitterDialogWrapper(@Nullable Project project, @NotNull StudyTwitterUtils.TwitterDialogPanel panel, DoNotAskOption doNotAskOption) {
+ super(project);
+ setTitle("Twitter");
+ setDoNotAskOption(doNotAskOption);
+ setOKButtonText("Tweet");
+ setCancelButtonText("No");
+ setResizable(true);
+ Dimension preferredSize = panel.getPreferredSize();
+ setSize((int) preferredSize.getHeight(), (int) preferredSize.getWidth());
+ myPanel = panel;
+ init();
+ }
+
+ public void setOKActionEnabled(boolean isEnabled) {
+ super.setOKActionEnabled(isEnabled);
+ }
+
+ @Nullable
+ @Override
+ protected JComponent createCenterPanel() {
+ return new JBScrollPane(myPanel);
+ }
+ }
+
/**
* Class provides structure for twitter dialog panel
*/
/**
* Provides tweet text
- * @return
*/
@NotNull public abstract String getMessage();
/**
- *
* @return Input stream of media should be posted or null if there's nothing to post
*/
@Nullable public abstract InputStream getMediaSource();
+
+ @Nullable public abstract String getMediaExtension();
/**
- *
* @return label that will be used to show remained symbol number
*/
@NotNull public abstract JLabel getRemainSymbolsLabel();
/**
* Api to add document listener to field containing tweet text
- * @param documentListener
*/
public abstract void addTextFieldVerifier(@NotNull final DocumentListener documentListener);