Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unobtrusive login #99

Merged
merged 22 commits into from
Apr 18, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
dc0870e
Added shortcut for getting a current user [API client]
meanmail Apr 15, 2017
f0f2c86
Added a login button in the Step Description if user is not authentic…
meanmail Apr 15, 2017
b9eef51
A login dialog will show only if user run a action explicit
meanmail Apr 15, 2017
6f96d0b
Divided the status to a action and a status [templates]
meanmail Apr 15, 2017
487df76
Added a load animation [Step Description]
meanmail Apr 15, 2017
0fe8410
Minor: delete excess html-tag [Step Description]
meanmail Apr 15, 2017
5c108b8
Added a sending logs from JavaScript to Java [Step Description]
meanmail Apr 15, 2017
4a3846d
Catch JavaScript exceptions [Step Description]
meanmail Apr 15, 2017
8e65b98
A language switch runs not inside Swing thread event queue
meanmail Apr 16, 2017
529318f
Actions on the toolpanel: send, download submissions, reset are enabl…
meanmail Apr 16, 2017
f3fcf3e
Update a progress when success authenticated or logout
meanmail Apr 16, 2017
ff5f3ad
Fixed a probably deadlock
meanmail Apr 16, 2017
bc22f16
Fixed NPE
meanmail Apr 16, 2017
cf8317b
Correct work a adaptive course-project if user is not authenticated
meanmail Apr 17, 2017
0e35ae0
Added auth states and a listening interface
meanmail Apr 17, 2017
8b9e38d
Don't reset selected step if user is not auth
meanmail Apr 17, 2017
2c440a4
Closing open files when user get new recommendation
meanmail Apr 17, 2017
ac6a597
Show load animation when user send a reaction [Adaptive]
meanmail Apr 17, 2017
a468cbb
Start to repair a project when a user login
meanmail Apr 17, 2017
475b717
Unobtrusive a login when use project wizard
meanmail Apr 17, 2017
440092b
When user push a Next button then show a login dialog [IDEA Wizard]
meanmail Apr 17, 2017
5a9eb65
Set a login button caption when auth state change [Project Wizard Panel]
meanmail Apr 17, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import org.jetbrains.annotations.NotNull;
import org.stepik.api.client.StepikApiClient;
import org.stepik.api.objects.users.User;
import org.stepik.api.queries.stepiks.StepikStepiksGetQuery;

/**
Expand All @@ -16,4 +17,10 @@ public StepikStepiksAction(@NotNull StepikApiClient stepikApiClient) {
public StepikStepiksGetQuery get() {
return new StepikStepiksGetQuery(this);
}

public User getCurrentUser() {
return this.get()
.id(1)
.execute().getUser();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
*/
public class Metric {
private String name;
private Integer timestamp;
private Long timestamp;
private Map<String, String> tags;
private Map<String, Object> data;

Expand Down Expand Up @@ -57,11 +57,11 @@ public void setName(@Nullable String name) {
}

@Nullable
public Integer getTimestamp() {
public Long getTimestamp() {
return timestamp;
}

public void setTimestamp(@Nullable Integer timestamp) {
public void setTimestamp(@Nullable Long timestamp) {
this.timestamp = timestamp;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public StepikMetricsPostQuery name(@NotNull String name) {
}

@NotNull
public StepikMetricsPostQuery timestamp(int value) {
public StepikMetricsPostQuery timestamp(long value) {
metrics.getMetric().setTimestamp(value);
return this;
}
Expand Down
143 changes: 115 additions & 28 deletions stepik-union/src/main/java/org/stepik/core/StepikProjectManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@

import com.google.gson.internal.LinkedTreeMap;
import com.intellij.ide.projectView.ProjectView;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.PersistentStateComponent;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.components.State;
import com.intellij.openapi.components.Storage;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.module.ModifiableModuleModel;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.module.ModuleWithNameAlreadyExists;
Expand All @@ -17,6 +20,8 @@
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.thoughtworks.xstream.XStream;
Expand All @@ -29,6 +34,7 @@
import org.jdom.output.XMLOutputter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.stepik.api.client.StepikApiClient;
import org.stepik.api.objects.StudyObject;
import org.stepik.api.objects.courses.Course;
import org.stepik.api.objects.lessons.CompoundUnitLesson;
Expand All @@ -48,6 +54,9 @@
import org.stepik.core.serialization.StudySerializationUtils;
import org.stepik.core.serialization.StudyUnrecognizedFormatException;
import org.stepik.core.serialization.SupportedLanguagesConverter;
import org.stepik.core.stepik.StepikAuthManager;
import org.stepik.core.stepik.StepikAuthManagerListener;
import org.stepik.core.stepik.StepikAuthState;
import org.stepik.core.ui.StudyToolWindow;
import org.stepik.plugin.projectWizard.idea.SandboxModuleBuilder;
import org.w3c.dom.Document;
Expand All @@ -61,12 +70,19 @@
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import static java.nio.charset.StandardCharsets.UTF_8;
import static org.stepik.core.stepik.StepikAuthManager.authAndGetStepikApiClient;
import static org.stepik.core.stepik.StepikAuthManager.isAuthenticated;
import static org.stepik.core.stepik.StepikAuthState.AUTH;
import static org.stepik.core.stepik.StepikAuthState.NOT_AUTH;
import static org.stepik.core.stepik.StepikAuthState.SHOW_DIALOG;
import static org.stepik.core.utils.ProjectFilesUtils.getOrCreateSrcDirectory;

@State(name = "StepikStudySettings", storages = @Storage("stepik_study_project.xml"))
public class StepikProjectManager implements PersistentStateComponent<Element>, DumbAware {
public class StepikProjectManager implements PersistentStateComponent<Element>, DumbAware, StepikAuthManagerListener, Disposable {
private static final int CURRENT_VERSION = 4;
private static final Logger logger = Logger.getInstance(StepikProjectManager.class);
@XStreamOmitField
Expand All @@ -81,6 +97,9 @@ public class StepikProjectManager implements PersistentStateComponent<Element>,
private static DOMBuilder domBuilder;
@XStreamOmitField
private final Project project;
@XStreamOmitField
private final ExecutorService executor = Executors.newSingleThreadExecutor();
@Nullable
private StudyNode<?, ?> root;
private StudyNode<?, ?> selected;
private boolean showHint = false;
Expand All @@ -91,6 +110,10 @@ public class StepikProjectManager implements PersistentStateComponent<Element>,

public StepikProjectManager(@Nullable Project project) {
this.project = project;
StepikAuthManager.addListener(this);
if (project != null) {
Disposer.register(project, this);
}
}

public StepikProjectManager() {
Expand Down Expand Up @@ -216,8 +239,32 @@ public static boolean isAdaptive(Project project) {
return instance != null && instance.isAdaptive();
}

public static void updateAdaptiveSelected(@Nullable Project project) {
if (project == null) {
return;
}
StepikProjectManager instance = getInstance(project);
if (instance != null) {
instance.updateAdaptiveSelected();
}
}

private void updateAdaptiveSelected() {
if (isAdaptive() && root != null) {
StudyNode<?, ?> recommendation = StudyUtils.getRecommendation(root);
if (selected == null || (recommendation != null && selected.getParent() != recommendation.getParent())) {
ApplicationManager.getApplication().invokeAndWait(() -> {
for (VirtualFile file : FileEditorManager.getInstance(project).getOpenFiles()) {
FileEditorManager.getInstance(project).closeFile(file);
}
});
setSelected(recommendation);
}
}
}

@Nullable
public StudyNode<?, ?> getSelected() {
private StudyNode<?, ?> getSelected() {
return selected;
}

Expand All @@ -242,7 +289,7 @@ public void setSelected(@Nullable StudyNode<?, ?> selected, boolean force) {
}
}

public void updateSelection() {
private void updateSelection() {
setSelected(selected, true);
}

Expand Down Expand Up @@ -300,56 +347,72 @@ public void loadState(Element state) {
}
}

public boolean isAdaptive() {
private boolean isAdaptive() {
if (root == null) {
return false;
}
StudyObject data = root.getData();
return data != null && data.isAdaptive();
}

private void refreshCourse() {
if (getProjectRoot() == null || project == null) {
if (project == null || root == null) {
return;
}

root.setProject(project);

new Thread(() -> {
root.reloadData(project);
ProgressManager.getInstance().run(new Task.Backgroundable(project, "Synchronize project") {
executor.execute(() -> {
StepikApiClient stepikApiClient = authAndGetStepikApiClient();
if (isAuthenticated()) {
root.reloadData(project, stepikApiClient);
}
ProgressManager.getInstance().run(new Task.Backgroundable(project, "Synchronize Project") {
@Override
public void run(@NotNull ProgressIndicator indicator) {
repairProjectFiles(root);
if (project.isDisposed()) {
return;
}

repairProjectFiles(root);
repairSandbox();

ApplicationManager.getApplication().invokeLater(() -> {
VirtualFileManager.getInstance().syncRefresh();
setSelected(selected, false);
}
);
}

private void repairSandbox() {
VirtualFile projectDir = project.getBaseDir();
if (projectDir != null && projectDir.findChild(EduNames.SANDBOX_DIR) == null) {
ModifiableModuleModel model = ModuleManager.getInstance(project)
.getModifiableModel();

ApplicationManager.getApplication().runWriteAction(() -> {
try {
new SandboxModuleBuilder(projectDir.getPath()).createModule(model);
model.commit();
} catch (IOException | ConfigurationException | JDOMException | ModuleWithNameAlreadyExists e) {
logger.warn("Failed repair Sandbox", e);
}
});
Application application = ApplicationManager.getApplication();

ModifiableModuleModel model = application.runReadAction(
(Computable<ModifiableModuleModel>) () -> ModuleManager.getInstance(project)
.getModifiableModel());


application.invokeLater(() ->
application.runWriteAction(() -> {
try {
new SandboxModuleBuilder(projectDir.getPath()).createModule(model);
model.commit();
} catch (IOException | ConfigurationException | JDOMException | ModuleWithNameAlreadyExists e) {
logger.warn("Failed repair Sandbox", e);
}
})
);
}

ApplicationManager.getApplication().invokeLater(() ->
VirtualFileManager.getInstance().syncRefresh()
);
}
});
}).start();
});
}

private void repairProjectFiles(@NotNull StudyNode<?, ?> node) {
if (project != null) {
if (node instanceof StepNode) {
if (project.isDisposed()) {
return;
}
ApplicationManager.getApplication().invokeAndWait(() -> {
if (project.isDisposed()) {
return;
Expand Down Expand Up @@ -431,4 +494,28 @@ public int hashCode() {
result = 31 * result + (uuid != null ? uuid.hashCode() : 0);
return result;
}

@Override
public void stateChanged(@NotNull StepikAuthState oldState, @NotNull StepikAuthState newState) {
if (newState == NOT_AUTH || newState == AUTH) {
if (root != null) {
root.resetStatus();
if (newState == AUTH) {
refreshCourse();
}
}

if (oldState == SHOW_DIALOG && newState == NOT_AUTH) {
setSelected(selected, false);
} else {
updateSelection();
}
}
}

@Override
public void dispose() {
StepikAuthManager.removeListener(this);
executor.shutdown();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.project.DumbAwareRunnable;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.startup.StartupManager;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.wm.ToolWindow;
import com.intellij.openapi.wm.ToolWindowAnchor;
Expand All @@ -21,11 +22,9 @@
import javafx.application.Platform;
import org.jetbrains.annotations.NotNull;
import org.stepik.core.actions.StudyActionWithShortcut;
import org.stepik.core.courseFormat.StudyNode;
import org.stepik.core.metrics.Metrics;
import org.stepik.core.ui.StudyToolWindow;
import org.stepik.core.ui.StudyToolWindowFactory;
import org.stepik.plugin.actions.navigation.StudyNavigator;

import javax.swing.*;
import java.util.ArrayList;
Expand Down Expand Up @@ -72,6 +71,10 @@ public void projectOpened() {
registerShortcuts();
}));
Metrics.openProject(project, SUCCESSFUL);

StartupManager.getInstance(project).runWhenProjectIsInitialized(() ->
executor.execute(() -> StepikProjectManager.updateAdaptiveSelected(project)
));
}

public void registerStudyToolWindow() {
Expand All @@ -86,33 +89,6 @@ public void registerStudyToolWindow() {
studyToolWindow.show(null);
StudyUtils.initToolWindows(project);
}

executor.execute(() -> {
StepikProjectManager projectManager = StepikProjectManager.getInstance(project);
if (projectManager == null) {
return;
}

StudyNode root = projectManager.getProjectRoot();

StudyNode<?, ?> selected = projectManager.getSelected();
if (root != null) {
if (projectManager.isAdaptive()) {
StudyNode<?, ?> recommendation = StudyUtils.getRecommendation(root);
if (recommendation == null) {
selected = null;
} else if (selected == null || selected.getParent() != recommendation.getParent()) {
selected = recommendation;
}
}

if (selected == null) {
selected = StudyNavigator.nextLeaf(root);
}

projectManager.setSelected(selected);
}
});
}

private void registerShortcuts() {
Expand Down
Loading