Skip to content
This repository was archived by the owner on Jun 3, 2025. It is now read-only.

Commit 4792045

Browse files
author
irenenikk
authored
Merge pull request #398 from testmycode/analytics
Add analytics and refactor system design
2 parents d653793 + 2a8ae77 commit 4792045

File tree

66 files changed

+1615
-659
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

66 files changed

+1615
-659
lines changed

README.md

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,14 @@ Once installation is complete, you can log in using `tmc login`. This saves your
8181
server address:
8282
username:
8383
password:
84-
Login successful.
84+
Choose organization by writing its slug:
85+
Do you want to send crash reports for client development? (Y/n)
86+
Do you want to send analytics data for research? (Y/n)
8587
```
8688

89+
You can change your organization with the command `organization`. Use the option `-o` and give the slug of an organization as an argument. Otherwise all available organizations will be listed.
90+
You can inspect and change your settings such as sending data with the command `config`. Use the option `-l` to see your current settings and give `[KEY]=[NEW VALUE]` as arguments to change them.
91+
8792
## Listing courses
8893

8994
Once you have logged in, you can list all the available courses on the server with `tmc courses`.
@@ -96,7 +101,7 @@ c-mooc
96101
javascript-for-lazy-hipsters
97102
```
98103

99-
Note that you can only submit exercises on courses for which you have enrolled.
104+
Note that you can only exercises on courses for which you have enrolled.
100105

101106
## Downloading courses
102107

@@ -127,7 +132,7 @@ All tests passed! Submit to server with 'tmc submit'
127132

128133
## Submitting exercises
129134

130-
You have now completed your first exercise! To submit your exercise, run `tmc submit`. The syntax is the same as for running tests.
135+
You have now completed your first exercise! To submit your exercise, run `tmc submit [exercise-name]` or run `tmc submit` in an exercise directory. The syntax is the same as for running tests.
131136

132137
```
133138
~/tmc-courses/test-course/exercise1 $ tmc submit

docs/MANUAL.md

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -126,12 +126,10 @@ COMMAND: SUBMIT
126126
`tmc` `submit` [`-a`] [`-d`] [`-c`] [*path*] ...
127127

128128
Submit exercises to the server. If no *path* is given, the exercise in the
129-
current working directory will be submitted. Several exercises can be submitted
130-
at once. If the current work directory is the course root directory or the
131-
course root directory was given as a *path*, then all exercises will be submitted.
129+
current working directory will be submitted. The submittable exercise(s) must be given as an argument.
132130

133131
For every successful submission, you'll be prompted to send feedback for the
134-
exercise if the course has enabledfeedback questions. Sending feedback is
132+
exercise if the course has enabled feedback questions. Sending feedback is
135133
always optional.
136134

137135
`-a` `--all`
@@ -192,7 +190,7 @@ Set or unset TMC-CLI properties. Only accepts certain keys. If not invoked with
192190
Do not ask for confirmations or print out set values.
193191

194192
`-l` `--list`
195-
List all current properties.
193+
List all current settings.
196194

197195
`-g` `--get=KEY` or `--get KEY`
198196
Get the value of a specific key.
@@ -206,8 +204,20 @@ List of configurable settings:
206204
blue, purple, cyan, white, none. Stored in properties.
207205
* *send-diagnostics*
208206
Allow sending crash reports and analytics for client development. Stored with account.
207+
* *send-analytics*
208+
Allow sending analytics data of commands run. Stored in account.
209209
* *server-address*
210-
Address to fetch courses from and submit to. Defaults to `https://tmc.mooc.fi`. Stored with account
210+
Address to fetch courses from and submit to. Defaults to `https://tmc.mooc.fi`. Stored with account. Changing the server address will log the user out and prompt a new login.
211+
212+
COMMAND: ORGANIZATION
213+
---------------
214+
215+
`tmc` `organization` [`-o`][*slug*] ...
216+
217+
Change organization, which determines the downloadable courses. If no slug is given, or the slug is invalid, all available organizations are listed, and the user will be prompted to choose one.
218+
219+
`-o` `--organization`
220+
Change organization to slug given as an argument without the listing of all organizations.
211221

212222
---
213223

docs/tmc.1

Lines changed: 42 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,12 @@ with a command, display a help message for that command.
3434
\l'\n(.lu'
3535
.SH COMMAND: LOGIN
3636
.PP
37-
\fB\fCtmc\fR \fB\fClogin\fR [\fB\fC\-s\fR \fIserver address\fP] [\fB\fC\-u\fR \fIusername\fP] [\fB\fC\-p\fR \fIpassword\fP]
37+
\fB\fCtmc\fR \fB\fClogin\fR [\fB\fC\-u\fR \fIusername\fP] [\fB\fC\-p\fR \fIpassword\fP]
3838
.PP
3939
Login to TMC server. If credentials are not given as options, the user will
4040
be asked to input any missing credentials. You will have to be logged in
4141
in order to use certain commands.
4242
.TP
43-
\fB\fC\-s\fR \fB\fC\-\-server\fR
44-
Specify which server to connect to.
45-
.TP
4643
\fB\fC\-u\fR \fB\fC\-\-user\fR
4744
Specify username.
4845
.TP
@@ -103,12 +100,12 @@ Display more detailed error messages.
103100
\fB\fCtmc\fR \fB\fCsubmit\fR [\fB\fC\-a\fR] [\fB\fC\-d\fR] [\fB\fC\-c\fR] [\fIpath\fP] ...
104101
.PP
105102
Submit exercises to the server. If no \fIpath\fP is given, the exercise in the
106-
current working directory will be submitted. Several exercises can be submitted
107-
at once. If the current work directory is the course root directory or the
108-
course root directory was given as a \fIpath\fP, then all exercises will be submitted.
103+
current working directory will be submitted. The submittable
104+
.BR exercise (s)
105+
must be given as an argument.
109106
.PP
110107
For every successful submission, you'll be prompted to send feedback for the
111-
exercise if the course has enabledfeedback questions. Sending feedback is
108+
exercise if the course has enabled feedback questions. Sending feedback is
112109
always optional.
113110
.TP
114111
\fB\fC\-a\fR \fB\fC\-\-all\fR
@@ -147,36 +144,62 @@ Do not send a message alongside the paste.
147144
.TP
148145
\fB\fC\-m\fR \fB\fC\-\-message\fR
149146
Give the message as an argument instead of opening a text editor.
150-
.SH COMMAND: PROP
147+
.SH COMMAND: CONFIG
151148
.PP
152-
\fB\fCtmc\fR \fB\fCprop\fR [\fIKEY\fP] [\fIVALUE\fP] ...
153-
\fB\fCprop\fR \fB\fC\-u\fR \fIKEY\fP ...
149+
\fB\fCtmc\fR \fB\fCconfig\fR \fB\fC[\-q]\fR[\fIKEY=VALUE\fP] ...
150+
\fB\fCconfig\fR \fB\fC\-d\fR \fB\fC[\-q]\fR [\fIKEY\fP] ...
151+
\fB\fCconfig\fR \fB\fC\-l\fR
152+
\fB\fCconfig\fR \fB\fC\-g\fR [\fIKEY\fP] or \fB\fC\-g\fR=[\fIKEY\fP]
154153
.PP
155-
Set or unset TMC\-CLI properties. Invoke without any arguments to display all
156-
current properties. If more than a single property is added or removed, the user
157-
will be asked to confirm the changes.
154+
Set or unset TMC\-CLI properties. Only accepts certain keys. If not invoked with the option \fB\fCquiet\fR will ask to confirm changes.
158155
.TP
159-
\fB\fC\-u\fR \fB\fC\-\-unset\fR
156+
\fB\fC\-d\fR \fB\fC\-\-delete\fR
160157
Unset given properties.
158+
.TP
159+
\fB\fC\-q\fR \fB\fC\-\-quiet\fR
160+
Do not ask for confirmations or print out set values.
161+
.TP
162+
\fB\fC\-l\fR \fB\fC\-\-list\fR
163+
List all current settings.
164+
.TP
165+
\fB\fC\-g\fR \fB\fC\-\-get=KEY\fR or \fB\fC\-\-get KEY\fR
166+
Get the value of a specific key.
161167
.PP
162-
List of properties:
168+
List of configurable settings:
163169
.RS
164170
.IP \(bu 2
165171
\fIupdate\-date\fP
166-
Scheduled time for the next version check.
172+
Scheduled time for the next version check. Stored in properties.
167173
.IP \(bu 2
168174
\fItestresults\-left\fP \fItestresults\-right\fP \fIprogressbar\-left\fP \fIprogressbar\-right\fP
169175
Change progress bar colours. Recognised values: black, red, green, yellow,
170-
blue, purple, cyan, white, none.
176+
blue, purple, cyan, white, none. Stored in properties.
177+
.IP \(bu 2
178+
\fIsend\-diagnostics\fP
179+
Allow sending crash reports and analytics for client development. Stored with account.
180+
.IP \(bu 2
181+
\fIsend\-analytics\fP
182+
Allow sending analytics data of commands run. Stored in account.
183+
.IP \(bu 2
184+
\fIserver\-address\fP
185+
Address to fetch courses from and submit to. Defaults to \fB\fChttps://tmc.mooc.fi\fR\&. Stored with account.
171186
.RE
187+
.SH COMMAND: ORGANIZATION
188+
.PP
189+
\fB\fCtmc\fR \fB\fCorganization\fR [\fB\fC\-o\fR][\fIslug\fP] ...
190+
.PP
191+
Change organization, which determines the downloadable courses. If no slug is given, or the slug is invalid, all available organizations are listed, and the user will be prompted to choose one.
192+
.PP
193+
\fB\fC\-o\fR \fB\fC\-\-organization\fR
194+
Change organization to slug given as an argument without the listing of all organizations.
172195
.ti 0
173196
\l'\n(.lu'
174197
.SH FILES
175198
.TP
176199
\fB\fC[course directory]/.tmc.json\fR
177200
Course configuration and cache file. Saves the status of the username, server
178201
address and course's exercises. Manually editing this file may have adverse
179-
effects.
202+
effects.
180203
.TP
181204
\fB\fC~/.config/tmc\-cli/properties.json\fR
182205
User configuration file. Use \fB\fCtmc prop\fR to edit properties.

src/main/java/fi/helsinki/cs/tmc/cli/Application.java

Lines changed: 60 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,29 @@
11
package fi.helsinki.cs.tmc.cli;
22

3+
import fi.helsinki.cs.tmc.cli.analytics.AnalyticsFacade;
4+
import fi.helsinki.cs.tmc.cli.analytics.TimeTracker;
5+
import fi.helsinki.cs.tmc.cli.backend.CourseInfo;
6+
import fi.helsinki.cs.tmc.cli.backend.Settings;
7+
import fi.helsinki.cs.tmc.cli.command.SubmitCommand;
38
import fi.helsinki.cs.tmc.cli.core.AbstractCommand;
49
import fi.helsinki.cs.tmc.cli.core.CliContext;
5-
import fi.helsinki.cs.tmc.cli.core.CommandFactory;
6-
import fi.helsinki.cs.tmc.cli.io.Color;
7-
import fi.helsinki.cs.tmc.cli.io.ColorUtil;
10+
import fi.helsinki.cs.tmc.cli.io.ShutdownHandler;
11+
import fi.helsinki.cs.tmc.cli.io.Io;
812
import fi.helsinki.cs.tmc.cli.io.EnvironmentUtil;
913
import fi.helsinki.cs.tmc.cli.io.HelpGenerator;
10-
import fi.helsinki.cs.tmc.cli.io.Io;
11-
import fi.helsinki.cs.tmc.cli.io.ShutdownHandler;
14+
import fi.helsinki.cs.tmc.cli.io.WorkDir;
1215
import fi.helsinki.cs.tmc.cli.updater.AutoUpdater;
16+
import fi.helsinki.cs.tmc.cli.core.CommandFactory;
1317

18+
19+
import fi.helsinki.cs.tmc.cli.utils.OptionalToGoptional;
20+
import fi.helsinki.cs.tmc.core.TmcCore;
21+
import fi.helsinki.cs.tmc.core.holders.TmcSettingsHolder;
22+
import fi.helsinki.cs.tmc.core.utilities.TmcRequestProcessor;
23+
import fi.helsinki.cs.tmc.langs.util.TaskExecutor;
24+
import fi.helsinki.cs.tmc.langs.util.TaskExecutorImpl;
25+
import fi.helsinki.cs.tmc.spyware.EventSendBuffer;
26+
import fi.helsinki.cs.tmc.spyware.EventStore;
1427
import org.apache.commons.cli.CommandLine;
1528
import org.apache.commons.cli.GnuParser;
1629
import org.apache.commons.cli.Option;
@@ -20,14 +33,7 @@
2033
import org.slf4j.Logger;
2134
import org.slf4j.LoggerFactory;
2235

23-
import java.lang.management.ManagementFactory;
24-
import java.util.List;
25-
import java.util.Map;
26-
import java.util.Set;
27-
import java.util.Scanner;
28-
import java.util.Date;
29-
import java.util.ArrayList;
30-
import java.util.Arrays;
36+
import java.util.*;
3137

3238
/**
3339
* The application class for the program.
@@ -47,7 +53,10 @@ public class Application {
4753
private String commandName;
4854
private boolean noAutoUpdate;
4955

56+
private TimeTracker timeTracker;
57+
5058
public Application(CliContext context) {
59+
this.timeTracker = new TimeTracker(context);
5160
this.parser = new GnuParser();
5261
this.options = new Options();
5362

@@ -88,11 +97,39 @@ private boolean runCommand(String name, String[] args) {
8897
io.errorln("Command " + name + " doesn't exist.");
8998
return false;
9099
}
100+
Optional<Thread> thread = sendAnalytics(command);
91101

92102
command.execute(context, args);
103+
joinNewThread(thread);
93104
return true;
94105
}
95106

107+
private Optional<Thread> sendAnalytics(AbstractCommand command) {
108+
Optional<Thread> thread = Optional.empty();
109+
if (command instanceof SubmitCommand || timeTracker.anHourHasPassedSinceLastSubmit()) {
110+
this.context.loadUserInformation(true);
111+
// get course info returns null
112+
CourseInfo courseInfo = this.context.getCourseInfo();
113+
if (courseInfo == null) {
114+
return Optional.empty();
115+
}
116+
TmcSettingsHolder.get().setCourse(OptionalToGoptional.convert(Optional.of(courseInfo.getCourse())));
117+
thread = this.context.getAnalyticsFacade().sendAnalytics();
118+
timeTracker.restart();
119+
}
120+
return thread;
121+
}
122+
123+
private void joinNewThread(Optional<Thread> thread) {
124+
thread.ifPresent(t -> {
125+
try {
126+
t.join();
127+
} catch (InterruptedException e) {
128+
logger.warn("Analytics thread interrupted");
129+
}
130+
});
131+
}
132+
96133
private String[] parseArgs(String[] args) {
97134
CommandLine line;
98135
try {
@@ -178,10 +215,16 @@ public void run(String[] args) {
178215
}
179216
}
180217

181-
182218
public static void main(String[] args) {
183-
Application app = new Application(new CliContext(null));
219+
Settings settings = new Settings();
220+
TaskExecutor tmcLangs = new TaskExecutorImpl();
221+
TmcCore core = new TmcCore(settings, tmcLangs);
222+
EventSendBuffer eventSendBuffer = new EventSendBuffer(settings, new EventStore());
223+
AnalyticsFacade analyticsFacade = new AnalyticsFacade(settings, eventSendBuffer);
224+
Application app = new Application(new CliContext(null, core, new WorkDir(), settings, analyticsFacade));
184225
app.run(args);
226+
// Because of EventSendBuffer
227+
TmcRequestProcessor.instance.shutdown();
185228
}
186229

187230
private boolean versionCheck() {
@@ -194,8 +237,8 @@ private boolean versionCheck() {
194237
try {
195238
time = Long.parseLong(previousTimestamp);
196239
} catch (NumberFormatException ex) {
197-
io.errorln("The previous update date isn't number.");
198-
logger.warn("The previous update date isn't number.", ex);
240+
io.errorln("The previous update date isn't a number.");
241+
logger.warn("The previous update date isn't a number.", ex);
199242
return false;
200243
}
201244
previous = new Date(time);
@@ -217,28 +260,7 @@ public boolean runAutoUpdate() {
217260
long timestamp = now.getTime();
218261
properties.put(previousUpdateDateKey, Long.toString(timestamp));
219262
context.saveProperties();
220-
221263
return updated;
222264
}
223265

224-
//TODO rename this as getColorProperty and move it somewhere else
225-
public Color getColor(String propertyName) {
226-
String propertyValue = context.getProperties().get(propertyName);
227-
Color color = ColorUtil.getColor(propertyValue);
228-
if (color == null) {
229-
switch (propertyName) {
230-
case "progressbar-left":
231-
return Color.CYAN;
232-
case "progressbar-right":
233-
return Color.CYAN;
234-
case "testresults-left":
235-
return Color.GREEN;
236-
case "testresults-right":
237-
return Color.RED;
238-
default:
239-
return Color.NONE;
240-
}
241-
}
242-
return color;
243-
}
244266
}

0 commit comments

Comments
 (0)