Skip to content

Commit a962d1d

Browse files
committed
feat: export csvs - students
#2103
1 parent 2fcaa29 commit a962d1d

File tree

8 files changed

+236
-73
lines changed

8 files changed

+236
-73
lines changed

pom-dependency-tree.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
ai.elimu:webapp:war:2.6.17-SNAPSHOT
1+
ai.elimu:webapp:war:2.6.20-SNAPSHOT
22
+- ai.elimu:model:jar:model-2.0.97:compile
33
| \- com.google.code.gson:gson:jar:2.13.0:compile
44
| \- com.google.errorprone:error_prone_annotations:jar:2.37.0:compile

src/main/java/ai/elimu/web/analytics/students/LetterSoundAssessmentEventCsvExportController.java renamed to src/main/java/ai/elimu/web/analytics/students/LetterSoundAssessmentEventsCsvExportController.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
@RequestMapping("/analytics/students/{studentId}/letter-sound-assessment-events.csv")
2323
@RequiredArgsConstructor
2424
@Slf4j
25-
public class LetterSoundAssessmentEventCsvExportController {
25+
public class LetterSoundAssessmentEventsCsvExportController {
2626

2727
private final StudentDao studentDao;
2828

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
package ai.elimu.web.analytics.students;
2+
3+
import ai.elimu.dao.LetterSoundLearningEventDao;
4+
import ai.elimu.dao.StudentDao;
5+
import ai.elimu.entity.analytics.LetterSoundLearningEvent;
6+
import ai.elimu.entity.analytics.students.Student;
7+
import jakarta.servlet.http.HttpServletResponse;
8+
import java.io.IOException;
9+
import java.io.OutputStream;
10+
import java.io.StringWriter;
11+
import java.util.List;
12+
import lombok.RequiredArgsConstructor;
13+
import lombok.extern.slf4j.Slf4j;
14+
import org.apache.commons.csv.CSVFormat;
15+
import org.apache.commons.csv.CSVPrinter;
16+
import org.springframework.stereotype.Controller;
17+
import org.springframework.web.bind.annotation.GetMapping;
18+
import org.springframework.web.bind.annotation.PathVariable;
19+
import org.springframework.web.bind.annotation.RequestMapping;
20+
21+
@Controller
22+
@RequestMapping("/analytics/students/{studentId}/letter-sound-learning-events.csv")
23+
@RequiredArgsConstructor
24+
@Slf4j
25+
public class LetterSoundLearningEventsCsvExportController {
26+
27+
private final StudentDao studentDao;
28+
29+
private final LetterSoundLearningEventDao letterSoundLearningEventDao;
30+
31+
@GetMapping
32+
public void handleRequest(
33+
@PathVariable Long studentId,
34+
HttpServletResponse response,
35+
OutputStream outputStream
36+
) throws IOException {
37+
log.info("handleRequest");
38+
39+
Student student = studentDao.read(studentId);
40+
log.info("student.getAndroidId(): " + student.getAndroidId());
41+
42+
List<LetterSoundLearningEvent> letterSoundLearningEvents = letterSoundLearningEventDao.readAll(student.getAndroidId());
43+
log.info("letterSoundLearningEvents.size(): " + letterSoundLearningEvents.size());
44+
45+
CSVFormat csvFormat = CSVFormat.DEFAULT.builder()
46+
.setHeader(
47+
"id",
48+
"timestamp",
49+
"package_name",
50+
// "letter_sound_letters",
51+
// "letter_sound_sounds",
52+
"letter_sound_id",
53+
"additional_data"
54+
)
55+
.build();
56+
57+
StringWriter stringWriter = new StringWriter();
58+
CSVPrinter csvPrinter = new CSVPrinter(stringWriter, csvFormat);
59+
60+
for (LetterSoundLearningEvent letterSoundLearningEvent : letterSoundLearningEvents) {
61+
log.info("letterSoundLearningEvent.getId(): " + letterSoundLearningEvent.getId());
62+
63+
csvPrinter.printRecord(
64+
letterSoundLearningEvent.getId(),
65+
letterSoundLearningEvent.getTimestamp().getTimeInMillis(),
66+
letterSoundLearningEvent.getPackageName(),
67+
// letterSoundLearningEvent.getLetterSoundLetters(),
68+
// letterSoundLearningEvent.getLetterSoundSounds(),
69+
letterSoundLearningEvent.getLetterSoundId(),
70+
letterSoundLearningEvent.getAdditionalData()
71+
);
72+
}
73+
csvPrinter.flush();
74+
csvPrinter.close();
75+
76+
String csvFileContent = stringWriter.toString();
77+
78+
response.setContentType("text/csv");
79+
byte[] bytes = csvFileContent.getBytes();
80+
response.setContentLength(bytes.length);
81+
try {
82+
outputStream.write(bytes);
83+
outputStream.flush();
84+
outputStream.close();
85+
} catch (IOException ex) {
86+
log.error(ex.getMessage());
87+
}
88+
}
89+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package ai.elimu.web.analytics.students;
2+
3+
import ai.elimu.dao.StoryBookLearningEventDao;
4+
import ai.elimu.dao.StudentDao;
5+
import ai.elimu.dao.WordLearningEventDao;
6+
import ai.elimu.entity.analytics.students.Student;
7+
import ai.elimu.util.AnalyticsHelper;
8+
import lombok.RequiredArgsConstructor;
9+
import lombok.extern.slf4j.Slf4j;
10+
11+
import java.util.List;
12+
13+
import org.springframework.stereotype.Controller;
14+
import org.springframework.ui.Model;
15+
import org.springframework.web.bind.annotation.GetMapping;
16+
import org.springframework.web.bind.annotation.RequestMapping;
17+
18+
@Controller
19+
@RequestMapping("/analytics/students")
20+
@RequiredArgsConstructor
21+
@Slf4j
22+
public class StudentListController {
23+
24+
private final StudentDao studentDao;
25+
26+
@GetMapping
27+
public String handleRequest(Model model) {
28+
log.info("handleRequest");
29+
30+
List<Student> students = studentDao.readAll();
31+
log.info("students.size(): " + students.size());
32+
for (Student student : students) {
33+
student.setAndroidId(AnalyticsHelper.redactAndroidId(student.getAndroidId()));
34+
}
35+
model.addAttribute("students", students);
36+
37+
return "analytics/students/list";
38+
}
39+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package ai.elimu.web.analytics.students;
2+
3+
import ai.elimu.dao.StudentDao;
4+
import ai.elimu.entity.analytics.students.Student;
5+
import ai.elimu.util.AnalyticsHelper;
6+
import jakarta.servlet.http.HttpServletResponse;
7+
import java.io.IOException;
8+
import java.io.OutputStream;
9+
import java.io.StringWriter;
10+
import java.util.List;
11+
import lombok.RequiredArgsConstructor;
12+
import lombok.extern.slf4j.Slf4j;
13+
import org.apache.commons.csv.CSVFormat;
14+
import org.apache.commons.csv.CSVPrinter;
15+
import org.springframework.stereotype.Controller;
16+
import org.springframework.web.bind.annotation.GetMapping;
17+
import org.springframework.web.bind.annotation.RequestMapping;
18+
19+
@Controller
20+
@RequestMapping("/analytics/students/students.csv")
21+
@RequiredArgsConstructor
22+
@Slf4j
23+
public class StudentsCsvExportController {
24+
25+
private final StudentDao studentDao;
26+
27+
@GetMapping
28+
public void handleRequest(
29+
HttpServletResponse response,
30+
OutputStream outputStream
31+
) throws IOException {
32+
log.info("handleRequest");
33+
34+
List<Student> students = studentDao.readAll();
35+
log.info("students.size(): " + students.size());
36+
for (Student student : students) {
37+
student.setAndroidId(AnalyticsHelper.redactAndroidId(student.getAndroidId()));
38+
}
39+
40+
CSVFormat csvFormat = CSVFormat.DEFAULT.builder()
41+
.setHeader(
42+
"id",
43+
"android_id"
44+
)
45+
.build();
46+
47+
StringWriter stringWriter = new StringWriter();
48+
CSVPrinter csvPrinter = new CSVPrinter(stringWriter, csvFormat);
49+
50+
for (Student student : students) {
51+
log.info("student.getId(): " + student.getId());
52+
53+
csvPrinter.printRecord(
54+
student.getId(),
55+
student.getAndroidId()
56+
);
57+
}
58+
csvPrinter.flush();
59+
csvPrinter.close();
60+
61+
String csvFileContent = stringWriter.toString();
62+
63+
response.setContentType("text/csv");
64+
byte[] bytes = csvFileContent.getBytes();
65+
response.setContentLength(bytes.length);
66+
try {
67+
outputStream.write(bytes);
68+
outputStream.flush();
69+
outputStream.close();
70+
} catch (IOException ex) {
71+
log.error(ex.getMessage());
72+
}
73+
}
74+
}

src/main/java/ai/elimu/web/analytics/students/StudentsListController.java

Lines changed: 0 additions & 66 deletions
This file was deleted.

src/main/webapp/WEB-INF/jsp/analytics/students/id.jsp

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@
1414
<div class="card-content">
1515
<p class="grey-text">Student ID</p>
1616
#${student.id}<br />
17-
<br />
18-
<p class="grey-text">Android ID</p>
17+
18+
<p class="grey-text" style="margin-top: 1em;">Android ID</p>
1919
<code>${student.androidId}</code>
2020
</div>
2121
</div>
@@ -128,12 +128,24 @@
128128
});
129129
});
130130
</script>
131-
<h5>Assessment events (${fn:length(letterSoundAssessmentEvents)})</h5>
131+
<h5>Letter-sound assessment events (${fn:length(letterSoundAssessmentEvents)})</h5>
132132
...
133133

134134
<div class="divider" style="margin: 2em 0;"></div>
135135

136-
<h5>Learning events (${fn:length(letterSoundLearningEvents)})</h5>
136+
<a id="exportLetterSoundLearningEventsToCsvButton" class="right btn waves-effect waves-light grey-text white"
137+
href="<spring:url value='/analytics/students/${student.id}/letter-sound-learning-events.csv' />">
138+
Export to CSV<i class="material-icons right">vertical_align_bottom</i>
139+
</a>
140+
<script>
141+
$(function() {
142+
$('#exportLetterSoundLearningEventsToCsvButton').click(function() {
143+
console.info('#exportLetterSoundLearningEventsToCsvButton click');
144+
Materialize.toast('Preparing CSV file. Please wait...', 4000, 'rounded');
145+
});
146+
});
147+
</script>
148+
<h5>Letter-sound learning events (${fn:length(letterSoundLearningEvents)})</h5>
137149
...
138150
</div>
139151
<div style="clear: both;"></div>

src/main/webapp/WEB-INF/jsp/analytics/students/list.jsp

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,22 @@
2222
</content:banner>
2323

2424
<content:section cssId="studentListPage">
25-
<div class="section row">
25+
<div class="row">
26+
<a id="exportStudentsToCsvButton" class="right btn waves-effect waves-light grey-text white"
27+
href="<spring:url value='/analytics/students/students.csv' />">
28+
Export to CSV<i class="material-icons right">vertical_align_bottom</i>
29+
</a>
30+
<script>
31+
$(function() {
32+
$('#exportStudentsToCsvButton').click(function() {
33+
console.info('#exportLetterSoundAssessmentEventsToCsvButton click');
34+
Materialize.toast('Preparing CSV file. Please wait...', 4000, 'rounded');
35+
});
36+
});
37+
</script>
38+
<h5>Students (${fn:length(students)})</h5>
39+
</div>
40+
<div class="row">
2641
<table class="bordered highlight">
2742
<thead>
2843
<th>Student ID</th>

0 commit comments

Comments
 (0)