Skip to content

Commit

Permalink
reactivate clan pages
Browse files Browse the repository at this point in the history
  • Loading branch information
fcaps committed Nov 23, 2023
1 parent 0a42c9e commit 55dc0a9
Show file tree
Hide file tree
Showing 25 changed files with 478 additions and 534 deletions.
3 changes: 2 additions & 1 deletion Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ module.exports = function(grunt) {
grunt.registerTask('prod', [
'sass:dist',
'concat:js',
'uglify:dist'
'uglify:dist',
'copy'
]);
};
5 changes: 3 additions & 2 deletions fafApp.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,7 @@ module.exports.setup = (app) => {
app.set('views', 'templates/views')
app.set('view engine', 'pug')
app.set('port', appConfig.expressPort)

app.use(middleware.injectServices)

app.use(middleware.initLocals)

app.use(express.static('public', {
Expand All @@ -88,6 +87,8 @@ module.exports.setup = (app) => {
}))
app.use(passport.initialize())
app.use(passport.session())
app.use(middleware.injectServices)

app.use(flash())
app.use(middleware.username)
app.use(copyFlashHandler)
Expand Down
2 changes: 1 addition & 1 deletion grunt/concurrent.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module.exports = {
dev: {
tasks: ['nodemon', 'concat', 'watch'],
tasks: ['nodemon', 'concat', 'watch', 'copy'],
options: {
logConcurrentOutput: true
}
Expand Down
24 changes: 24 additions & 0 deletions grunt/copy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
module.exports = {
js: {
files:[
{
expand: true,
cwd: 'node_modules/simple-datatables/dist',
src: 'module.js',
dest: 'public/js/',
rename: function(dest, src) {
return dest + 'simple-datatables.js'
}
},
{
expand: true,
cwd: 'node_modules/simple-datatables/dist',
src: 'style.css',
dest: 'public/styles/css/',
rename: function(dest, src) {
return dest + 'simple-datatables.css'
}
}
]
}
}
135 changes: 135 additions & 0 deletions lib/clan/ClanRepository.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
class ClanRepository {
constructor(javaApiClient) {
this.javaApiClient = javaApiClient
}

async fetchAll() {
const response = await this.javaApiClient.get('/data/clan?sort=createTime&include=leader&fields[clan]=name,tag,description,leader,memberships,createTime&fields[player]=login&page[number]=1&page[size]=3000')

if (response.status !== 200) {
throw new Error('ClanRepository::fetchAll failed with response status "' + response.status + '"')
}

const responseData = JSON.parse(response.data)

if (typeof responseData !== 'object' || responseData === null) {
throw new Error('ClanRepository::fetchAll malformed response, not an object')
}

if (!responseData.hasOwnProperty('data')) {
throw new Error('ClanRepository::fetchAll malformed response, expected "data"')
}

if (responseData.data.length === 0) {
console.log('[info] clans empty')

return []
}

if (!responseData.hasOwnProperty('included')) {
throw new Error('ClanRepository::fetchAll malformed response, expected "included"')
}

const clans = responseData.data.map((item, index) => ({
id: parseInt(item.id),
leaderName: responseData.included[index].attributes.login,
name: item.attributes.name,
tag: item.attributes.tag,
createTime: item.attributes.createTime,
description: item.attributes.description,
population: item.relationships.memberships.data.length
}))

clans.sort((a, b) => {
if (a.population > b.population) {
return -1
}
if (a.population < b.population) {
return 1
}

return 0
});

return await clans
}

async fetchClan(id) {
let response = await this.javaApiClient.get(`/data/clan/${id}?include=memberships.player`)

if (response.status !== 200) {
throw new Error('ClanRepository::fetchClan failed with response status "' + response.status + '"')
}

const data = JSON.parse(response.data)

if (typeof data !== 'object' || data === null) {
throw new Error('ClanRepository::fetchClan malformed response, not an object')
}

if (!data.hasOwnProperty('data')) {
throw new Error('ClanRepository::fetchClan malformed response, expected "data"')
}

if (typeof data.data !== 'object' || data.data === null) {
return null
}

if (typeof data.included !== 'object' || data.included === null) {
throw new Error('ClanRepository::fetchClan malformed response, expected "included"')
}

const clanRaw = data.data.attributes

const clan = {
id: data.data.id,
name: clanRaw.name,
tag: clanRaw.tag,
description: clanRaw.description,
createTime: clanRaw.createTime,
requiresInvitation: clanRaw.requiresInvitation,
tagColor: clanRaw.tagColor,
updateTime: clanRaw.updateTime,
founder: null,
leader: null,
memberships: {},
}

let members = {};

for (let k in data.included) {
switch (data.included[k].type) {
case "player":
const player = data.included[k];
if (!members[player.id]) members[player.id] = {};
members[player.id].id = player.id;
members[player.id].name = player.attributes.login;

if (player.id === data.data.relationships.leader.data.id) {
clan.leader = members[player.id]
}

if (player.id === data.data.relationships.founder.data.id) {
clan.founder = members[player.id]
}

break;

case "clanMembership":
const membership = data.included[k];
const member = membership.relationships.player.data;
if (!members[member.id]) members[member.id] = {};
members[member.id].id = member.id;
members[member.id].membershipId = membership.id;
members[member.id].joinedAt = membership.attributes.createTime;
break;
}
}

clan.memberships = members

return clan
}
}

module.exports = ClanRepository
43 changes: 43 additions & 0 deletions lib/clan/ClanService.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
const {MutexService} = require("../MutexService");
const clanTTL = 60 * 5

class ClanService {
constructor(cacheService, clanRepository, lockTimeout = 3000) {
this.lockTimeout = lockTimeout
this.cacheService = cacheService
this.mutexService = new MutexService()
this.clanRepository = clanRepository
}

getCacheKey(name) {
return 'ClanService_' + name
}

async getClan(id) {
return this.clanRepository.fetchClan(id)
}

async getAll() {

const cacheKey = this.getCacheKey('all')

if (this.cacheService.has(cacheKey)) {
return this.cacheService.get(cacheKey)
}

if (this.mutexService.locked) {
await this.mutexService.acquire(() => {
}, this.lockTimeout)
return this.getAll()
}

await this.mutexService.acquire(async () => {
const result = await this.clanRepository.fetchAll()
this.cacheService.set(cacheKey, result, clanTTL);
})

return this.getAll()
}
}

module.exports = ClanService
14 changes: 14 additions & 0 deletions lib/clan/ClanServiceFactory.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
const ClanService = require("./ClanService")
const ClanRepository = require("./ClanRepository")
const {Axios} = require("axios")
const cacheService = require('../CacheService')

module.exports = (javaApiBaseURL, token) => {
const config = {
baseURL: javaApiBaseURL,
headers: {Authorization: `Bearer ${token}`}
};
const clanClient = new Axios(config)

return new ClanService(cacheService, new ClanRepository(clanClient))
}
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"express": "^4.18.1",
"express-session": "^1.17.3",
"express-validator": "7.0.1",
"grunt-contrib-copy": "^1.0.0",
"moment": "^2.29.4",
"node-cache": "^5.1.2",
"node-fetch": "^2.6.7",
Expand All @@ -21,6 +22,7 @@
"request": "2.88.2",
"session-file-store": "^1.5.0",
"showdown": "^2.1.0",
"simple-datatables": "^8.0.1",
"supertest-session": "^5.0.1",
"url-slug": "^4.0.1"
},
Expand Down
5 changes: 5 additions & 0 deletions public/js/app/clan.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import('/js/simple-datatables.js').then(({DataTable}) => {
new DataTable("#clan-members", {
perPageSelect: null
})
})
Loading

0 comments on commit 55dc0a9

Please sign in to comment.