mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2025-03-14 07:00:01 -04:00
Create and list clans
Replace mock data with some real functionality.
This commit is contained in:
parent
32b48a3c4c
commit
482b66b8a4
12 changed files with 257 additions and 111 deletions
7
app/models/Clan.coffee
Normal file
7
app/models/Clan.coffee
Normal file
|
@ -0,0 +1,7 @@
|
|||
CocoModel = require './CocoModel'
|
||||
schema = require 'schemas/models/clan.schema'
|
||||
|
||||
module.exports = class Clan extends CocoModel
|
||||
@className: 'Clan'
|
||||
@schema: schema
|
||||
urlRoot: '/db/clan'
|
23
app/schemas/models/clan.schema.coffee
Normal file
23
app/schemas/models/clan.schema.coffee
Normal file
|
@ -0,0 +1,23 @@
|
|||
c = require './../schemas'
|
||||
|
||||
ClanSchema = c.object {title: 'Clan', required: ['name', 'type']}
|
||||
c.extendNamedProperties ClanSchema # name first
|
||||
|
||||
_.extend ClanSchema.properties,
|
||||
name: c.shortString()
|
||||
type: {type: 'string', 'enum': ['public']}
|
||||
ownerID: c.objectId()
|
||||
ownerName: c.shortString()
|
||||
members: c.array {title: 'Members'},
|
||||
c.object {required: ['id', 'name', 'level']},
|
||||
id: c.objectId()
|
||||
name: c.shortString()
|
||||
level: {type: 'integer'}
|
||||
|
||||
c.extendBasicProperties ClanSchema, 'Clan'
|
||||
|
||||
# Do we need these?
|
||||
# c.extendSearchableProperties ClanSchema
|
||||
# c.extendPermissionsProperties ClanSchema
|
||||
|
||||
module.exports = ClanSchema
|
|
@ -2,41 +2,36 @@ extends /templates/base
|
|||
|
||||
block content
|
||||
|
||||
ol.breadcrumb
|
||||
li
|
||||
a(href="/")
|
||||
span.glyphicon.glyphicon-home
|
||||
li
|
||||
a(href="/clans") Clans
|
||||
|
||||
li.active= clan.title
|
||||
|
||||
h1= clan.title
|
||||
h1= clan.get('name')
|
||||
span.spr.spl.small (owner
|
||||
a(href="/user/#{clan.get('ownerID')}")= clan.get('ownerName')
|
||||
| )
|
||||
div
|
||||
span Owner:
|
||||
a(href="/user/#{clan.ownerID}")= clan.owner
|
||||
div Members: #{clan.memberCount}
|
||||
if clan.owner === 'mrsmith'
|
||||
div
|
||||
if isOwner
|
||||
button.btn.btn-sm.btn-warning Delete Clan
|
||||
else if isMember
|
||||
button.btn.btn-sm.btn-warning Leave Clan
|
||||
else
|
||||
button.btn.btn-sm.btn-success Join Clan
|
||||
|
||||
h3 Clan Members
|
||||
table.table.table-striped.table-condensed
|
||||
thead
|
||||
tr
|
||||
th Name
|
||||
th Level
|
||||
th
|
||||
tbody
|
||||
each member in members
|
||||
if clan.get('members')
|
||||
h3 Clan Members (#{clan.get('members').length})
|
||||
table.table.table-striped.table-condensed
|
||||
thead
|
||||
tr
|
||||
td
|
||||
a(href="/user/#{member.id}")= member.name
|
||||
td= member.level
|
||||
if member.name !== clan.owner && clan.owner === 'mrsmith'
|
||||
td
|
||||
button.btn.btn-sm.btn-warning Remove Member
|
||||
else
|
||||
th Name
|
||||
th Level
|
||||
th
|
||||
tbody
|
||||
each member in clan.get('members')
|
||||
tr
|
||||
td
|
||||
a(href="/user/#{member.id}")= member.name
|
||||
td= member.level
|
||||
if member.id !== clan.get('ownerID')
|
||||
td
|
||||
button.btn.btn-sm.btn-warning Remove Member
|
||||
else
|
||||
td
|
||||
|
||||
button.btn.btn-sm Load More
|
||||
button.btn.btn-sm Load More
|
||||
|
|
|
@ -2,16 +2,10 @@ extends /templates/base
|
|||
|
||||
block content
|
||||
|
||||
ol.breadcrumb
|
||||
li
|
||||
a(href="/")
|
||||
span.glyphicon.glyphicon-home
|
||||
li.active Clans
|
||||
|
||||
div
|
||||
button.btn.btn-sm.btn-success Create New Clan
|
||||
button.btn.btn-sm.btn-success.create-clan-btn Create New Clan
|
||||
span.spr.spl
|
||||
input(type='text' placeholder='New clan name')
|
||||
input.create-clan-name(type='text' placeholder='New clan name')
|
||||
br
|
||||
|
||||
div(role='tabpanel')
|
||||
|
@ -31,21 +25,23 @@ block content
|
|||
th Owner
|
||||
th
|
||||
tbody
|
||||
each clan in publicClans
|
||||
tr
|
||||
td
|
||||
if clan.owner === 'mrsmith'
|
||||
a(href="/clans/#{clan.id}", style='font-weight:bold')= clan.title
|
||||
else
|
||||
a(href="/clans/#{clan.id}")= clan.title
|
||||
td= clan.memberCount
|
||||
td
|
||||
a(href="/user/#{clan.ownerID}")= clan.owner
|
||||
td
|
||||
if !clan.member
|
||||
button.btn.btn-sm.btn-success Join Clan
|
||||
else if clan.owner !== 'mrsmith'
|
||||
button.btn.btn-sm.btn-warning Leave Clan
|
||||
if publicClans.length
|
||||
each clan in publicClans
|
||||
tr
|
||||
td
|
||||
if clan.get('ownerID') === me.id
|
||||
a(href="/clans/#{clan.id}", style='font-weight:bold')= clan.get('name')
|
||||
else
|
||||
a(href="/clans/#{clan.id}")= clan.get('name')
|
||||
td= clan.get('members').length
|
||||
td
|
||||
a(href="/user/#{clan.ownerID}")= clan.get('ownerName')
|
||||
td
|
||||
if myClanIDs.indexOf(clan.id) < 0
|
||||
button.btn.btn-sm.btn-success Join Clan
|
||||
else if clan.get('ownerID') !== me.id
|
||||
button.btn.btn-sm.btn-warning Leave Clan
|
||||
|
||||
button.btn.btn-sm Load More
|
||||
|
||||
.tab-pane#my-clans(role='tabpanel')
|
||||
|
@ -57,18 +53,16 @@ block content
|
|||
th Owner
|
||||
th
|
||||
tbody
|
||||
each clan in myClans
|
||||
tr
|
||||
td
|
||||
if clan.owner === 'mrsmith'
|
||||
a(href="/clans/#{clan.id}", style='font-weight:bold')= clan.title
|
||||
else
|
||||
a(href="/clans/#{clan.id}")= clan.title
|
||||
td= clan.memberCount
|
||||
td
|
||||
a(href="/user/#{clan.ownerID}")= clan.owner
|
||||
td
|
||||
if clan.owner !== 'mrsmith'
|
||||
button.btn.btn-sm.btn-warning Leave Clan
|
||||
if myClans.length
|
||||
each clan in myClans
|
||||
tr
|
||||
td
|
||||
a(href="/clans/#{clan.id}")= clan.get('name')
|
||||
td= clan.get('members').length
|
||||
td
|
||||
a(href="/user/#{clan.ownerID}")= clan.get('ownerName')
|
||||
td
|
||||
if clan.get('ownerID') !== me.id
|
||||
button.btn.btn-sm.btn-warning Leave Clan
|
||||
|
||||
button.btn.btn-sm Load More
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
RootView = require 'views/core/RootView'
|
||||
template = require 'templates/clans/clan-details'
|
||||
Clan = require 'models/Clan'
|
||||
|
||||
module.exports = class ClanDetailsView extends RootView
|
||||
id: 'clan-details-view'
|
||||
|
@ -7,24 +8,12 @@ module.exports = class ClanDetailsView extends RootView
|
|||
|
||||
constructor: (options, @clanID) ->
|
||||
super options
|
||||
@initMockData()
|
||||
@clan = new Clan _id: @clanID
|
||||
@supermodel.loadModel @clan, 'clan', cache: false
|
||||
|
||||
getRenderData: =>
|
||||
context = super()
|
||||
context.clan = @clan
|
||||
context.members = @members
|
||||
context.isOwner = @clan.get('ownerID') is me.id
|
||||
context.isMember = _.find(@clan.get('members'), (m) -> m.id is me.id) ? false
|
||||
context
|
||||
|
||||
initMockData: ->
|
||||
@clan =
|
||||
title: 'Slay more munchkins'
|
||||
owner: 'mrsmith'
|
||||
memberCount: 8
|
||||
ownerID: me.get('_id')
|
||||
|
||||
@members = [
|
||||
{id: me.get('_id'), name: 'mrsmith', level: 24}
|
||||
{id: me.get('_id'), name: 'Superman', level: 2}
|
||||
{id: me.get('_id'), name: 'batman', level: 1}
|
||||
{id: me.get('_id'), name: 'Bruce', level: 4}
|
||||
]
|
||||
|
|
|
@ -1,41 +1,40 @@
|
|||
app = require 'core/application'
|
||||
RootView = require 'views/core/RootView'
|
||||
template = require 'templates/clans/clans'
|
||||
CocoCollection = require 'collections/CocoCollection'
|
||||
Clan = require 'models/Clan'
|
||||
|
||||
module.exports = class MainAdminView extends RootView
|
||||
id: 'clans-view'
|
||||
template: template
|
||||
|
||||
events:
|
||||
'click .clan-title': 'onClickClanTitle'
|
||||
'click .create-clan-btn': 'onClickCreateClan'
|
||||
|
||||
constructor: (options) ->
|
||||
super options
|
||||
@initMockData()
|
||||
@publicClans = new CocoCollection([], { url: '/db/clan', model: Clan, comparator:'_id' })
|
||||
@supermodel.loadCollection(@publicClans, 'public_clans', {cache: false})
|
||||
|
||||
getRenderData: ->
|
||||
context = super()
|
||||
context.myClans = @myClans
|
||||
context.publicClans = @publicClans
|
||||
context.publicClans = @publicClans.models
|
||||
context.myClans = @publicClans.where({ownerID: me.get('_id')})
|
||||
context.myClanIDs = _.map context.myClans, (c) -> c.id
|
||||
context
|
||||
|
||||
onClickClanTitle: (e) ->
|
||||
if clanID = $(e.target).data('id')
|
||||
app.router.navigate "/clans/#{clanID}"
|
||||
onClickCreateClan: (e) ->
|
||||
if name = $('.create-clan-name').val()
|
||||
# TODO: async creating message
|
||||
clan = new Clan()
|
||||
clan.set 'type', 'public'
|
||||
clan.set 'name', name
|
||||
clan.save {},
|
||||
error: (model, response, options) =>
|
||||
console.error 'Error saving clan', response
|
||||
success: (model, response, options) =>
|
||||
app.router.navigate "/clans/#{model.id}"
|
||||
window.location.reload()
|
||||
else
|
||||
console.error "No clan ID found for public clan row."
|
||||
|
||||
initMockData: ->
|
||||
@myClans = [
|
||||
{id: 1, title: 'FC Dallas', owner: 'soccerfan', memberCount: 4, member: true, ownerID: me.get('_id')}
|
||||
{id: 2, title: 'Mr. Smith 4th period', owner: 'mrsmith', memberCount: 23, member: true, ownerID: me.get('_id')}
|
||||
{id: 3, title: 'Test Title 21', owner: 'matt', memberCount: 12, member: true, ownerID: me.get('_id')}
|
||||
{id: 4, title: 'Slay more munchkins', owner: 'mrsmith', memberCount: 8, member: true, ownerID: me.get('_id')}
|
||||
]
|
||||
|
||||
@publicClans = [
|
||||
{id: 1, title: 'FC Dallas', owner: 'soccerfan', memberCount: 4, member: true, ownerID: me.get('_id')}
|
||||
{id: 2, title: 'Mr. Smith 4th period', owner: 'mrsmith', memberCount: 23, member: true, ownerID: me.get('_id')}
|
||||
{id: 5, title: 'tourney tanks', owner: 'jkl324', memberCount: 7, member: false, ownerID: me.get('_id')}
|
||||
{id: 6, title: 'Pythonistas', owner: 'bob219', memberCount: 50, member: false, ownerID: me.get('_id')}
|
||||
]
|
||||
# TODO: Invalid name message
|
||||
console.log 'Invalid name'
|
||||
|
|
21
server/clans/Clan.coffee
Normal file
21
server/clans/Clan.coffee
Normal file
|
@ -0,0 +1,21 @@
|
|||
mongoose = require 'mongoose'
|
||||
log = require 'winston'
|
||||
config = require '../../server_config'
|
||||
plugins = require '../plugins/plugins'
|
||||
jsonSchema = require '../../app/schemas/models/clan.schema'
|
||||
|
||||
ClanSchema = new mongoose.Schema {}, {strict: false, minimize: false, read:config.mongo.readpref}
|
||||
|
||||
ClanSchema.statics.privateProperties = []
|
||||
ClanSchema.statics.editableProperties = [
|
||||
'type'
|
||||
'name'
|
||||
'members'
|
||||
]
|
||||
|
||||
ClanSchema.plugin plugins.NamedPlugin
|
||||
ClanSchema.plugin plugins.SearchablePlugin, {searchable: ['name']}
|
||||
|
||||
ClanSchema.statics.jsonSchema = jsonSchema
|
||||
|
||||
module.exports = Clan = mongoose.model 'clan', ClanSchema, 'clans'
|
31
server/clans/clan_handler.coffee
Normal file
31
server/clans/clan_handler.coffee
Normal file
|
@ -0,0 +1,31 @@
|
|||
async = require 'async'
|
||||
mongoose = require 'mongoose'
|
||||
Handler = require '../commons/Handler'
|
||||
Clan = require './Clan'
|
||||
|
||||
ClanHandler = class ClanHandler extends Handler
|
||||
modelClass: Clan
|
||||
jsonSchema: require '../../app/schemas/models/Clan.schema'
|
||||
allowedMethods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE']
|
||||
|
||||
hasAccess: (req) ->
|
||||
return true if req.method in ['GET']
|
||||
return true if req.user? and not req.user.isAnonymous()
|
||||
false
|
||||
|
||||
hasAccessToDocument: (req, document, method=null) ->
|
||||
method = (method or req.method).toLowerCase()
|
||||
return true if req.user?.isAdmin()
|
||||
return true if method is 'get'
|
||||
false
|
||||
|
||||
makeNewInstance: (req) ->
|
||||
instance = super(req)
|
||||
instance.set 'ownerID', req.user._id
|
||||
instance.set 'ownerName', req.user.name
|
||||
instance.set 'members', [
|
||||
{id: req.user._id, name: req.user.name, level: req.user.level()}
|
||||
]
|
||||
instance
|
||||
|
||||
module.exports = new ClanHandler()
|
|
@ -6,6 +6,7 @@ module.exports.handlers =
|
|||
# 'analytics_users_active': 'analytics/analytics_users_active_handler'
|
||||
'article': 'articles/article_handler'
|
||||
'campaign': 'campaigns/campaign_handler'
|
||||
'clan': 'clans/clan_handler'
|
||||
'level': 'levels/level_handler'
|
||||
'level_component': 'levels/components/level_component_handler'
|
||||
'level_feedback': 'levels/feedbacks/level_feedback_handler'
|
||||
|
@ -22,9 +23,9 @@ module.exports.handlers =
|
|||
'achievement': 'achievements/achievement_handler'
|
||||
'earned_achievement': 'achievements/earned_achievement_handler'
|
||||
'poll': 'polls/poll_handler'
|
||||
'user_polls_record': 'polls/user_polls_record_handler'
|
||||
'prepaid': 'prepaids/prepaid_handler'
|
||||
'subscription': 'payments/subscription_handler'
|
||||
'user_polls_record': 'polls/user_polls_record_handler'
|
||||
|
||||
module.exports.routes =
|
||||
[
|
||||
|
|
|
@ -27,6 +27,7 @@ models_path = [
|
|||
'../../server/analytics/AnalyticsUsersActive'
|
||||
'../../server/articles/Article'
|
||||
'../../server/campaigns/Campaign'
|
||||
'../../server/clans/Clan'
|
||||
'../../server/levels/Level'
|
||||
'../../server/levels/components/LevelComponent'
|
||||
'../../server/levels/systems/LevelSystem'
|
||||
|
@ -182,6 +183,10 @@ GLOBAL.loginUser = (user, done) ->
|
|||
form.append('username', user.get('email'))
|
||||
form.append('password', user.get('name'))
|
||||
|
||||
GLOBAL.logoutUser = (done) ->
|
||||
request.post getURL('/auth/logout'), ->
|
||||
done()
|
||||
|
||||
GLOBAL.dropGridFS = (done) ->
|
||||
if mongoose.connection.readyState is 2
|
||||
mongoose.connection.once 'open', ->
|
||||
|
|
81
test/server/functional/clan.spec.coffee
Normal file
81
test/server/functional/clan.spec.coffee
Normal file
|
@ -0,0 +1,81 @@
|
|||
config = require '../../../server_config'
|
||||
require '../common'
|
||||
utils = require '../../../app/core/utils' # Must come after require /common
|
||||
mongoose = require 'mongoose'
|
||||
|
||||
describe 'Clans', ->
|
||||
stripe = require('stripe')(config.stripe.secretKey)
|
||||
clanURL = getURL('/db/clan')
|
||||
|
||||
createClan = (type, name, done) ->
|
||||
requestBody =
|
||||
type: type
|
||||
name: name
|
||||
request.post {uri: clanURL, json: requestBody }, (err, res, body) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toBe(200)
|
||||
expect(body.type).toEqual(type)
|
||||
expect(body.name).toEqual(name)
|
||||
Clan.findById body._id, (err, clan) ->
|
||||
expect(clan.get('type')).toEqual(type)
|
||||
expect(clan.get('name')).toEqual(name)
|
||||
done(clan)
|
||||
|
||||
it 'Clear database users and clans', (done) ->
|
||||
clearModels [User, Clan], (err) ->
|
||||
throw err if err
|
||||
done()
|
||||
|
||||
it 'Create clan', (done) ->
|
||||
loginNewUser (user1) ->
|
||||
createClan 'public', 'myclan1', (clan) ->
|
||||
done()
|
||||
|
||||
it 'Anonymous create clan 401', (done) ->
|
||||
logoutUser ->
|
||||
requestBody =
|
||||
type: 'public'
|
||||
name: 'myclan1'
|
||||
request.post {uri: clanURL, json: requestBody }, (err, res, body) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toBe(401)
|
||||
done()
|
||||
|
||||
it 'Create clan missing type 422', (done) ->
|
||||
loginNewUser (user1) ->
|
||||
requestBody =
|
||||
name: 'myclan1'
|
||||
request.post {uri: clanURL, json: requestBody }, (err, res, body) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toBe(422)
|
||||
done()
|
||||
|
||||
it 'Create clan missing name 422', (done) ->
|
||||
loginNewUser (user1) ->
|
||||
requestBody =
|
||||
type: 'public'
|
||||
request.post {uri: clanURL, json: requestBody }, (err, res, body) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toBe(422)
|
||||
done()
|
||||
|
||||
it 'Get clans', (done) ->
|
||||
loginNewUser (user1) ->
|
||||
createClan 'public', 'myclan2', ->
|
||||
createClan 'public', 'myclan3', ->
|
||||
request.get {uri: clanURL }, (err, res, body) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toBe(200)
|
||||
expect(body.length).toBeGreaterThan(1)
|
||||
done()
|
||||
|
||||
it 'Get clans anonymous', (done) ->
|
||||
loginNewUser (user1) ->
|
||||
createClan 'public', 'myclan4', ->
|
||||
createClan 'public', 'myclan5', ->
|
||||
logoutUser ->
|
||||
request.get {uri: clanURL }, (err, res, body) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toBe(200)
|
||||
expect(body.length).toBeGreaterThan(1)
|
||||
done()
|
|
@ -46,7 +46,7 @@ describe '/db/payment', ->
|
|||
paymentCreated = body?._id
|
||||
expect(res.statusCode).toBe 201
|
||||
User.findOne({name:'Joe'}).exec(err, (err, user) ->
|
||||
expect(user.get('purchased').gems).toBe(5000)
|
||||
expect(user.get('purchased')?.gems).toBe(5000)
|
||||
done()
|
||||
)
|
||||
|
||||
|
@ -56,7 +56,7 @@ describe '/db/payment', ->
|
|||
expect(body._id is paymentCreated).toBe(true)
|
||||
expect(res.statusCode).toBe 200
|
||||
User.findOne({name:'Joe'}).exec(err, (err, user) ->
|
||||
expect(user.get('purchased').gems).toBe(5000)
|
||||
expect(user.get('purchased')?.gems).toBe(5000)
|
||||
done()
|
||||
)
|
||||
|
||||
|
@ -72,7 +72,7 @@ describe '/db/payment', ->
|
|||
expect(body._id is paymentCreated).toBe(false)
|
||||
expect(res.statusCode).toBe 201
|
||||
User.findOne({name:'Joe'}).exec(err, (err, user) ->
|
||||
expect(user.get('purchased').gems).toBe(16000)
|
||||
expect(user.get('purchased')?.gems).toBe(16000)
|
||||
done()
|
||||
)
|
||||
|
||||
|
|
Loading…
Reference in a new issue