Skip to content

Commit

Permalink
Merge pull request #1571 from NationalSecurityAgency/t#1559/last_repo…
Browse files Browse the repository at this point in the history
…rted_date

T#1559/last reported date
  • Loading branch information
dwalizer authored Aug 17, 2022
2 parents 0bb2fe6 + 03265a1 commit 4349ee9
Show file tree
Hide file tree
Showing 14 changed files with 138 additions and 56 deletions.
2 changes: 1 addition & 1 deletion dashboard/src/components/projects/ProjectCardFooter.vue
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ limitations under the License.
There are <span style="font-size: 1rem;"><b-badge variant="danger">{{ numIssues | number }}</b-badge></span> issues to address </span>
</div>
<div class="col text-right" data-cy="projectCreated">
<project-dates :created="project.created" :last-reported-skill="project.lastReportedSkill" />
<project-dates :created="project.created"/>
</div>
</div>
</div>
Expand Down
43 changes: 36 additions & 7 deletions dashboard/src/components/projects/ProjectDates.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,25 +16,54 @@ limitations under the License.
<template>
<span>
<span data-cy="projectCreated">
<span class="text-secondary small font-italic">Created: </span><slim-date-cell :value="created"/>
<span class="text-secondary small mx-2 d-none d-md-inline">|</span>
<span class="text-secondary small font-italic">Created: </span><slim-date-cell
:value="created"/>
<span v-if="loadLastReportedDate"
class="text-secondary small mx-2 d-none d-md-inline">|</span>
</span>
<br class="d-md-none"/>
<span data-cy=projectLastReportedSkill>
<span class="text-secondary small font-italic">Last Reported Skill: </span><slim-date-cell :value="lastReportedSkill" :fromStartOfDay="true"/>
<br v-if="loadLastReportedDate" class="d-md-none"/>
<span v-if="loadLastReportedDate" data-cy="projectLastReportedSkill">
<span class="text-secondary small font-italic">Last Reported Skill: </span>
<b-spinner v-if="isLoading" label="Loading..." small type="grow" variant="info"></b-spinner>
<slim-date-cell v-if="!isLoading" :value="lastReportedSkill" :fromStartOfDay="true"/>
</span>
</span>
</template>

<script>
import SlimDateCell from '../utils/table/SlimDateCell';
import SlimDateCell from '@/components/utils/table/SlimDateCell';
import ProjectService from '@/components/projects/ProjectService';
export default {
name: 'ProjectDates',
components: {
SlimDateCell,
},
props: ['created', 'lastReportedSkill'],
props: ['created', 'loadLastReportedDate'],
data() {
return {
isLoading: true,
lastReportedSkill: null,
};
},
mounted() {
this.doLoadDate();
},
methods: {
doLoadDate() {
if (this.loadLastReportedDate) {
ProjectService.getLatestSkillEventForProject(this.$route.params.projectId)
.then((res) => {
this.lastReportedSkill = res.lastReportedSkillDate;
})
.finally(() => {
this.isLoading = false;
});
} else {
this.isLoading = false;
}
},
},
};
</script>

Expand Down
2 changes: 1 addition & 1 deletion dashboard/src/components/projects/ProjectPage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ limitations under the License.
</div>
<div slot="subSubTitle" v-if="project">
<div data-cy="projectCreated">
<project-dates :created="project.created" :last-reported-skill="project.lastReportedSkill" />
<project-dates :created="project.created" :load-last-reported-date="true"/>
</div>
<b-button-group class="mt-3" size="sm">
<b-button @click="displayEditProject"
Expand Down
10 changes: 8 additions & 2 deletions dashboard/src/components/projects/ProjectService.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,15 +57,21 @@ export default {
return axios.get(`/admin/projects/${encodeURIComponent(projectId)}/errors`, { params }).then((response) => response.data);
},
deleteProjectError(projectId, errorType, reportedSkillid) {
return axios.delete(`/admin/projects/${encodeURIComponent(projectId)}/errors/${errorType}/${encodeURIComponent(reportedSkillid)}`).then((response) => response.data);
return axios.delete(`/admin/projects/${encodeURIComponent(projectId)}/errors/${errorType}/${encodeURIComponent(reportedSkillid)}`)
.then((response) => response.data);
},
deleteAllProjectErrors(projectId) {
return axios.delete(`/admin/projects/${encodeURIComponent(projectId)}/errors`).then((response) => response.data);
return axios.delete(`/admin/projects/${encodeURIComponent(projectId)}/errors`)
.then((response) => response.data);
},
getProjectDetails(projectId) {
return axios.get(`/admin/projects/${encodeURIComponent(projectId)}`)
.then((response) => response.data);
},
getLatestSkillEventForProject(projectId) {
return axios.get(`/admin/projects/${encodeURIComponent(projectId)}/lastSkillEvent`)
.then((response) => response.data);
},
updateProjectDisplaySortOrder(projectId, newDisplayOrderIndex) {
return axios.patch(`/admin/projects/${encodeURIComponent(projectId)}`, {
action: 'NewDisplayOrderIndex',
Expand Down
10 changes: 0 additions & 10 deletions dashboard/src/components/projects/ProjectsTable.vue
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,6 @@ limitations under the License.
<template v-slot:cell(numErrors)="data">
{{ data.value | number }}
</template>
<template v-slot:cell(lastReportedSkill)="data">
<slim-date-cell :value="data.value" :fromStartOfDay="true"/>
</template>

<template v-slot:cell(created)="data">
<div>
Expand Down Expand Up @@ -139,7 +136,6 @@ limitations under the License.
import MsgBoxMixin from '../utils/modal/MsgBoxMixin';
import ProjectService from './ProjectService';
import SkillsBTable from '../utils/table/SkillsBTable';
import SlimDateCell from '../utils/table/SlimDateCell';
import RemovalValidation from '../utils/modal/RemovalValidation';
import EditProject from './EditProject';
Expand Down Expand Up @@ -198,11 +194,6 @@ limitations under the License.
label: 'Badges',
sortable: true,
},
{
key: 'lastReportedSkill',
label: 'Last Reported Skill',
sortable: true,
},
{
key: 'created',
label: 'Created',
Expand All @@ -227,7 +218,6 @@ limitations under the License.
components: {
EditProject,
SkillsBTable,
SlimDateCell,
RemovalValidation,
},
mounted() {
Expand Down
31 changes: 5 additions & 26 deletions e2e-tests/cypress/integration/projects_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -909,32 +909,11 @@ describe('Projects Tests', () => {
cy.wait('@getProjects');
cy.wait('@loadInception');

cy.get('[data-cy=projectCreated]').should('be.visible').contains('Today');
cy.get('[data-cy=projectLastReportedSkill]').should('be.visible').contains('Never');

const now = dayjs().utc();
cy.reportSkill('my_project_123', 1, '[email protected]', now.subtract(1, 'year').format('YYYY-MM-DD HH:mm'), false);

cy.visit('/administrator/');
cy.wait('@getProjects');
cy.wait('@loadInception');
cy.get('[data-cy=projectCreated]').should('be.visible').contains('Today');
cy.get('[data-cy=projectLastReportedSkill]').should('be.visible').contains('a year ago');

cy.reportSkill('my_project_123', 1, '[email protected]', now.subtract(2, 'months').format('YYYY-MM-DD HH:mm'), false);
cy.visit('/administrator/');
cy.wait('@getProjects');
cy.wait('@loadInception');
cy.get('[data-cy=projectCreated]').should('be.visible').contains('Today');
cy.get('[data-cy=projectLastReportedSkill]').should('be.visible').contains('2 months ago');

cy.reportSkill('my_project_123', 1, '[email protected]', now.subtract(7, 'days').utc().format('YYYY-MM-DD HH:mm'), false);

cy.visit('/administrator/');
cy.wait('@getProjects');
cy.wait('@loadInception');
cy.get('[data-cy=projectCreated]').should('be.visible').contains('Today');
cy.get('[data-cy=projectLastReportedSkill]').should('be.visible').contains('7 days ago');
cy.get('[data-cy=projectCreated]')
.should('be.visible')
.contains('Today');
cy.get('[data-cy=projectLastReportedSkill]')
.should('not.exist');
});

it('Created and Last Reported Skill data should be visible on project page', () => {
Expand Down
4 changes: 0 additions & 4 deletions e2e-tests/cypress/integration/projects_table_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -325,10 +325,6 @@ describe('Projects Table Tests', () => {
colIndex: 4,
value: '0'
},
{
colIndex: 5,
value: '2 months ago'
},
],
], 1);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1412,6 +1412,12 @@ class AdminController {
return success
}

@RequestMapping(value = "/projects/{projectId}/lastSkillEvent", method = RequestMethod.GET, produces = "application/json")
LatestEvent getLatestEventForProject(@PathVariable("projectId") String projectId) {
SkillsValidator.isNotBlank(projectId, "projectId")
return projAdminService.getLastReportedSkillEvent(projectId)
}


}

Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* Copyright 2020 SkillTree
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package skills.controller.result.model

class LatestEvent {
Date lastReportedSkillDate
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import skills.controller.exceptions.ErrorCode
import skills.controller.exceptions.SkillException
import skills.controller.request.model.*
import skills.controller.result.model.CustomIconResult
import skills.controller.result.model.LatestEvent
import skills.controller.result.model.ProjectResult
import skills.controller.result.model.SettingsResult
import skills.controller.result.model.SimpleProjectResult
Expand Down Expand Up @@ -544,11 +545,16 @@ class ProjAdminService {
}

@Profile
private UserInfo loadCurrentUser(boolean failIfNoCurrentUser=true) {
private UserInfo loadCurrentUser(boolean failIfNoCurrentUser = true) {
UserInfo currentUser = userInfoService.getCurrentUser()
if (!currentUser && failIfNoCurrentUser) {
throw new SkillsAuthorizationException('No current user found')
}
return currentUser
}

LatestEvent getLastReportedSkillEvent(String projectId) {
Date date = eventsRepo.getLatestEventDateForProject(projectId)
new LatestEvent(lastReportedSkillDate: date)
}
}
4 changes: 0 additions & 4 deletions service/src/main/java/skills/storage/repos/ProjDefRepo.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -114,11 +114,9 @@ interface ProjDefRepo extends CrudRepository<ProjDef, Long> {
COALESCE(reusedSkills.reusedSkillCount, 0) AS numSkillsReused,
COALESCE(reusedSkills.reusedTotalPoints, 0) AS totalPointsReused,
expiration.expirationTriggeredDate as expirationTriggered,
events.latest AS lastReportedSkill,
pd.created,
GREATEST(skills.skillUpdated, badges.badgeUpdated, subjects.subjectUpdated, pd.updated) as lastEdited
FROM project_definition pd
LEFT JOIN (SELECT max(project_id) as project_id, MAX(event_time) AS latest FROM user_events where LOWER(project_id) = LOWER(?1)) events ON events.project_id = pd.project_id
LEFT JOIN (SELECT max(project_id) as project_id, COUNT(id) AS errorCount FROM project_error where LOWER(project_id) = LOWER(?1)) errors ON errors.project_id = pd.project_id
LEFT JOIN (SELECT max(project_id) as project_id, COUNT(id) AS skillCount, MAX(updated) as skillUpdated FROM skill_definition WHERE type = 'Skill' and enabled = 'false' and LOWER(project_id) = LOWER(?1)) disabledSkills ON disabledSkills.project_id = pd.project_id
LEFT JOIN (SELECT max(project_id) AS project_id, COUNT(id) AS skillCount, MAX(updated) as skillUpdated FROM skill_definition WHERE type = 'Skill' and enabled = 'true' and skill_id not like '%STREUSESKILLST%' and LOWER(project_id) = LOWER(?1)) skills ON skills.project_id = pd.project_id
Expand Down Expand Up @@ -181,12 +179,10 @@ interface ProjDefRepo extends CrudRepository<ProjDef, Long> {
COALESCE(groups.groupCount, 0) AS numGroups,
CAST(COALESCE(expiration.expiringUnused, 'false') AS BOOLEAN) as expiring,
expiration.expirationTriggeredDate as expirationTriggered,
events.latest AS lastReportedSkill,
reusedSkills.skillCount AS numSkillsReused,
reusedSkills.totalPoints AS totalPointsReused,
pd.created
FROM project_definition pd
LEFT JOIN (SELECT project_id, MAX(event_time) AS latest FROM user_events GROUP BY project_id) events ON events.project_id = pd.project_id
LEFT JOIN (SELECT project_id, COUNT(id) AS errorCount FROM project_error GROUP BY project_id) errors ON errors.project_id = pd.project_id
LEFT JOIN (SELECT project_id, COUNT(id) AS skillCount FROM skill_definition WHERE type = 'Skill' and skill_id not like '%STREUSESKILLST%' and enabled = 'true' GROUP BY project_id) skills ON skills.project_id = pd.project_id
LEFT JOIN (SELECT project_id, COUNT(id) AS skillCount, sum(total_points) as totalPoints FROM skill_definition WHERE type = 'Skill' and skill_id like '%STREUSESKILLST%' and enabled = 'true' GROUP BY project_id) reusedSkills ON reusedSkills.project_id = pd.project_id
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -469,4 +469,10 @@ interface UserEventsRepo extends CrudRepository<UserEvent, Integer> {
) AS counts GROUP BY counts.countBucket;
''', nativeQuery = true)
public List<LabeledCount> binnedUserCountsForSkillUsagePostAchievement(@Param("skillRefId") Integer skillRefId)

@Nullable
@Query(value = '''
SELECT max(event_time) FROM user_events where project_id = ?1
''', nativeQuery = true)
Date getLatestEventDateForProject(String projectId)
}
44 changes: 44 additions & 0 deletions service/src/test/java/skills/intTests/UserAdminMetricsSpec.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,48 @@ class UserAdminMetricsSpec extends DefaultIntSpec {
metrics.numSkills == 2
metrics.userTotalPoints == 70
}

def "get latest event date for a project"() {
List<String> users = getRandomUsers(3)

def proj1 = SkillsFactory.createProject(1)
def proj1_subj = SkillsFactory.createSubject(1, 1)
List<Map> proj1_skills = SkillsFactory.createSkills(3, 1, 1)
proj1_skills.each {
it.pointIncrement = 35
}

skillsService.createProject(proj1)
skillsService.createSubject(proj1_subj)
skillsService.createSkills(proj1_skills)

List<Date> dates = (10..1).collect { new Date() - it }

skillsService.addSkill([projectId: proj1.projectId, skillId: proj1_skills.get(0).skillId], users[0], dates[0])
skillsService.addSkill([projectId: proj1.projectId, skillId: proj1_skills.get(1).skillId], users[1], dates[1])
skillsService.addSkill([projectId: proj1.projectId, skillId: proj1_skills.get(1).skillId], users[2], dates[2])

when:
def lastSkillEvent = skillsService.getLastSkillEventForProject(proj1.projectId)
then:
Date.parse("yyyy-MM-dd'T'HH:mm:ss.SSS", lastSkillEvent.lastReportedSkillDate) == dates[2].clearTime()
}

def "get latest event date is null for a project without any events"() {
def proj1 = SkillsFactory.createProject(1)
def proj1_subj = SkillsFactory.createSubject(1, 1)
List<Map> proj1_skills = SkillsFactory.createSkills(3, 1, 1)
proj1_skills.each {
it.pointIncrement = 35
}

skillsService.createProject(proj1)
skillsService.createSubject(proj1_subj)
skillsService.createSkills(proj1_skills)

when:
def lastSkillEvent = skillsService.getLastSkillEventForProject(proj1.projectId)
then:
lastSkillEvent.lastReportedSkillDate == null
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -895,6 +895,10 @@ class SkillsService {
return wsHelper.adminGet("/projects/${projectId}/users/${userId}/stats".toString())
}

def getLastSkillEventForProject(String projectId) {
return wsHelper.adminGet("/projects/${projectId}/lastSkillEvent".toString())
}

def getSkillUsers(String projectId, String skillId, int limit = 10, int page = 1, String orderBy = 'userId', boolean ascending = true, String query = '') {
return wsHelper.adminGet("${getSkillUrl(projectId, null, skillId)}/users?limit=${limit}&ascending=${ascending ? 1 : 0}&page=${page}&byColumn=0&orderBy=${orderBy}&query=${query}".toString())
}
Expand Down

0 comments on commit 4349ee9

Please sign in to comment.