зеркало из https://github.com/mozilla/CSOL-site.git
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
Коммит
bfc37b1a17
|
@ -1,3 +1,12 @@
|
|||
# Chicago Summer of Learning
|
||||
|
||||
The website for the Chicago Summer of Learning, developed by Ocupop and Mozilla.
|
||||
|
||||
## Environment
|
||||
|
||||
Property | Default | Description
|
||||
-------|-------|----------
|
||||
`CSOL_DB_NAME` | `"csol"` | Name of the database.
|
||||
`CSOL_DB_USER` | `"root"` | Database username.
|
||||
`CSOL_DB_PASS` | `null` | Database password.
|
||||
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
const Sequelize = require('sequelize');
|
||||
|
||||
const DB_NAME = process.env['CSOL_DB_NAME'] || 'csol';
|
||||
const USERNAME = process.env['CSOL_DB_USER'] || 'root';
|
||||
const PASSWORD = process.env['CSOL_DB_PASS'];
|
||||
|
||||
const db = new Sequelize(DB_NAME, USERNAME, PASSWORD, {
|
||||
define: { charset: 'utf8' }
|
||||
});
|
||||
|
||||
db.type = Sequelize;
|
||||
module.exports = db;
|
|
@ -0,0 +1,14 @@
|
|||
const db = require('../db.js');
|
||||
|
||||
const Organization = db.define('Organization', {
|
||||
id: { type: db.type.INTEGER, primaryKey: true, autoIncrement: true },
|
||||
name: { type: db.type.STRING, allowNull: false, unique: true },
|
||||
description: { type: db.type.STRING, allowNull: false, unique: true },
|
||||
url: { type: db.type.STRING, allowNull: false, validate: { isUrl: true }},
|
||||
imageUrl: { type: db.type.TEXT, allowNull: false, validate: { isUrl: true }},
|
||||
address: { type: db.type.TEXT, allowNull: true },
|
||||
phone: { type: db.type.STRING, allowNull: true },
|
||||
email: { type: db.type.STRING, allowNull: true, validate: { isEmail: true }},
|
||||
});
|
||||
|
||||
module.exports = Organization;
|
|
@ -5,7 +5,11 @@
|
|||
"main": "app.js",
|
||||
"dependencies": {
|
||||
"express": "~3.1.0",
|
||||
"nunjucks": "~0.1.8a"
|
||||
"nunjucks": "~0.1.8a",
|
||||
"mysql": "~2.0.0-alpha7",
|
||||
"sequelize": "~1.6.0",
|
||||
"tap": "~0.4.1",
|
||||
"async": "~0.2.6"
|
||||
},
|
||||
"devDependencies": {},
|
||||
"scripts": {
|
||||
|
|
|
@ -66,11 +66,11 @@ body {
|
|||
text-align: center;
|
||||
line-height: .8em;
|
||||
}
|
||||
#navigation ul {
|
||||
#navigation .nav {
|
||||
margin-bottom: 0;
|
||||
display: inline-block;
|
||||
}
|
||||
#navigation ul li a {
|
||||
#navigation .nav li > a {
|
||||
text-transform: uppercase;
|
||||
margin: 0;
|
||||
padding: 10px 30px 10px 30px;
|
||||
|
@ -82,16 +82,35 @@ body {
|
|||
-webkit-background-clip: padding-box;
|
||||
background-clip: padding-box;
|
||||
color: #404041;
|
||||
border-right: 1px solid #404041;
|
||||
border: none;
|
||||
border-left: 1px solid #404041;
|
||||
}
|
||||
#navigation ul li a:hover {
|
||||
#navigation .nav li > a:hover {
|
||||
background: #eee;
|
||||
}
|
||||
#navigation ul li.active a {
|
||||
#navigation .nav li.active a {
|
||||
background: #eee;
|
||||
}
|
||||
#navigation ul li:last-child a {
|
||||
border-right: none;
|
||||
#navigation .nav li:first-child a {
|
||||
border-left: none;
|
||||
}
|
||||
#navigation .nav ul li a {
|
||||
border: none;
|
||||
}
|
||||
#navigation .nav form {
|
||||
padding: 10px;
|
||||
text-align: left;
|
||||
}
|
||||
#navigation .nav form .btn {
|
||||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
#navigation .nav form small {
|
||||
margin-top: 10px;
|
||||
border-top: solid 1px #CCC;
|
||||
display: block;
|
||||
clear: both;
|
||||
text-align: center;
|
||||
}
|
||||
ul.row {
|
||||
list-style: none;
|
||||
|
|
|
@ -1,13 +1,33 @@
|
|||
html,body{margin:0;padding:0;background:#EEE;}
|
||||
html,body{margin:0;padding:0;background-image:url('../images/billie_holiday.png');}@media all and (-webkit-min-device-pixel-ratio:1.5){html,body{background-image:url('../images/billie_holiday@2x.png');background-size:100px 100px;}}
|
||||
#notes{position:fixed;bottom:1em;right:1em;max-width:300px;padding:1em;background:rgba(255, 255, 255, 0.75);color:#333;border:solid 1px #999;box-shadow:2px 2px 5px rgba(0, 0, 0, 0.5);}
|
||||
#header{background:#EEE;border-bottom:solid 1px #CCC;position:relative;}#header::after{content:"";position:absolute;top:100%;left:0;width:100%;height:5px;background:-webkit-linear-gradient(top, rgba(0, 0, 0, 0.25), rgba(0, 0, 0, 0));}
|
||||
#header h1{margin:0;overflow:hidden;font-size:2em;line-height:2em;}#header h1 a{display:block;float:left;width:220px;height:100px;background:rgba(0, 0, 0, 0.05);text-indent:-999em;overflow:hidden;position:relative;border-right:solid 1px rgba(255, 255, 255, 0.75);box-shadow:inset 2px 2px 5px rgba(0, 0, 0, 0.125);}#header h1 a::after{content:"CSOL";display:block;position:absolute;top:50%;left:0;width:100%;height:2em;margin-top:-1em;text-align:center;text-indent:0;color:rgba(0, 0, 0, 0.25);text-shadow:1px 1px 1px rgba(255, 255, 255, 0.5);}
|
||||
#navigation{line-height:3em;margin:-3em 0 0;}#navigation ul{margin-bottom:0;}
|
||||
#content{padding:50px 0;min-height:200px;background:#FFF;}
|
||||
#footer{border-top:solid 1px #CCC;height:100px;}
|
||||
#header{background:url(../images/chalkboard_bg_green.jpg) center;position:relative;-webkit-box-shadow:inset 0px -10px 20px 0px rgba(0, 0, 0, 0.25);-moz-box-shadow:inset 0px -10px 20px 0px rgba(0, 0, 0, 0.25);box-shadow:inset 0px -10px 20px 0px rgba(0, 0, 0, 0.25);}#header::after{position:absolute;top:100%;left:0;width:100%;height:5px;background:-webkit-linear-gradient(top, rgba(0, 0, 0, 0.25), rgba(0, 0, 0, 0));}
|
||||
#header h1{margin:0;overflow:hidden;font-size:2em;line-height:2em;display:block;}#header h1 a{display:block;max-width:671px;height:220px;background:url(../images/csol_logo_illustration.png) center no-repeat;background-size:100%;text-indent:-999em;position:relative;margin:23px auto 0 auto;}
|
||||
#navigation{margin:0 auto;position:relative;bottom:-16px;margin-top:-12px;-webkit-box-shadow:0 0 8px 3px rgba(0, 0, 0, 0.25);-moz-box-shadow:0 0 8px 3px rgba(0, 0, 0, 0.25);box-shadow:0 0 8px 3px rgba(0, 0, 0, 0.25);background:white;text-align:center;line-height:.8em;}#navigation .nav{margin-bottom:0;display:inline-block;}#navigation .nav li>a{text-transform:uppercase;margin:0;padding:10px 30px 10px 30px;font-size:1.2em;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-moz-background-clip:padding;-webkit-background-clip:padding-box;background-clip:padding-box;color:#404041;border:none;border-left:1px solid #404041;}#navigation .nav li>a:hover{background:#eee;}
|
||||
#navigation .nav li.active a{background:#eee;}
|
||||
#navigation .nav li:first-child a{border-left:none;}
|
||||
#navigation .nav ul li a{border:none;}
|
||||
#navigation .nav form{padding:10px;text-align:left;}#navigation .nav form .btn{display:block;width:100%;}
|
||||
#navigation .nav form small{margin-top:10px;border-top:solid 1px #CCC;display:block;clear:both;text-align:center;}
|
||||
ul.row{list-style:none;}
|
||||
figure.thumbnail{margin:0;}
|
||||
.thumbnail img{margin-top:5px;}
|
||||
.thumbnail>a{display:block;text-align:center;}
|
||||
form .divider{display:block;margin:2em 0;text-align:center;position:relative;}form .divider::before{content:"";position:absolute;left:0;top:50%;width:100%;border-top:solid 1px #CCC;}
|
||||
form .divider em{background:#FFF;padding:0 1em;position:relative;}
|
||||
#content{text-shadow:1px 1px 0px rgba(255, 255, 255, 0.4);padding:50px 0;min-height:200px;}#content h2{text-transform:uppercase;font-family:"ff-meta-web-pro";font-weight:bold;display:block;margin:0 auto;text-align:center;margin-bottom:40px;padding-bottom:8px;padding-top:8px;position:relative;}#content h2::before{content:"";position:absolute;left:0;top:50%;width:35%;border-top:solid 1px black;}
|
||||
#content h2::after{content:"";position:absolute;right:0;top:50%;width:35%;border-top:solid 1px black;}
|
||||
.navbar-form{color:white;text-shadow:1px 1px 0px black;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-moz-background-clip:padding;-webkit-background-clip:padding-box;background-clip:padding-box;border:none;background:url(../images/chalkboard_bg_grey.jpg) center;}.navbar-form .brand{text-transform:uppercase;padding-left:12px;padding-top:9px;}
|
||||
.thumbnails figure{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-moz-background-clip:padding;-webkit-background-clip:padding-box;background-clip:padding-box;background:white;-webkit-box-shadow:0 0 5px 1px rgba(0, 0, 0, 0.3);-moz-box-shadow:0 0 5px 1px rgba(0, 0, 0, 0.3);box-shadow:0 0 5px 1px rgba(0, 0, 0, 0.3);padding:0;margin:0;border:none;}.thumbnails figure figcaption{background:#555555 url(../images/chalkboard_bg_grey.jpg) center;color:white !important;text-shadow:none;}
|
||||
.thumbnails figure img{padding:15px ;}
|
||||
.btn{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-moz-background-clip:padding;-webkit-background-clip:padding-box;background-clip:padding-box;}
|
||||
#footer{border-top:solid 1px #CCC;min-height:100px;background:url(../images/chalkboard_bg_green.jpg) center;position:relative;-webkit-box-shadow:inset 0px 10px 20px 0px rgba(0, 0, 0, 0.25);-moz-box-shadow:inset 0px 10px 20px 0px rgba(0, 0, 0, 0.25);box-shadow:inset 0px 10px 20px 0px rgba(0, 0, 0, 0.25);color:white;font-size:1.1em;}#footer .toprow{border-bottom:1px solid white;padding-bottom:20px;margin-bottom:25px;}#footer .toprow .pull-left{font-size:1.1em;padding-top:10px;}
|
||||
#footer a{color:white;}#footer a:hover{background-color:none;}
|
||||
#footer .nav{font-size:1.2em;text-transform:uppercase;margin:0;padding:0;}#footer .nav li{margin-bottom:0;padding:0;}#footer .nav li a{display:inline-block;}#footer .nav li a:hover{background:none;}
|
||||
#footer .container{padding:40px 0;}
|
||||
#footer .logo-csol{width:100%;height:131px;background:url(../images/csol_logo_footer.png) center no-repeat;text-indent:-999em;display:block;margin-bottom:20px;margin-right:15px;}
|
||||
#footer .logos{text-align:center;}
|
||||
#footer .description{margin-bottom:20px;}
|
||||
#footer .logo{text-indent:-999em;display:inline-block;padding:10px;margin:5px;background-repeat:no-repeat;}#footer .logo.macarthur{width:78px;height:78px;background-image:url(../images/footer_logo_macarthur.png);}
|
||||
#footer .logo.city{width:78px;height:78px;background-image:url(../images/footer_logo_citiofchi.png);}
|
||||
#footer .logo.mozilla{width:82px;height:78px;background-image:url(../images/footer_logo_mozilla.png);background-position:10px 20px;}
|
||||
@media all and (max-width:767px){#header h1{padding:10px 20px;min-height:130px;}#header h1 a{height:150px;} #content{padding:20px 20px;}#content h2:before,#content h2:after{border:none;} #footer{padding:0 20px;}#footer .pull-left{float:none;text-align:center;margin-bottom:20px;} #footer nav{float:none;text-align:center;}#footer nav li{display:inline-block;}}
|
||||
|
|
|
@ -71,20 +71,21 @@ body {
|
|||
text-align: center;
|
||||
line-height: .8em;
|
||||
|
||||
ul {
|
||||
.nav {
|
||||
margin-bottom: 0;
|
||||
display: inline-block;
|
||||
|
||||
li {
|
||||
|
||||
a {
|
||||
& > a {
|
||||
text-transform: uppercase;
|
||||
margin: 0;
|
||||
padding: 10px 30px 10px 30px;
|
||||
font-size: 1.2em;
|
||||
.border-radius(0);
|
||||
color: #404041;
|
||||
border-right: 1px solid #404041;
|
||||
border: none;
|
||||
border-left: 1px solid #404041;
|
||||
|
||||
&:hover {
|
||||
background: #eee;
|
||||
|
@ -94,17 +95,39 @@ body {
|
|||
|
||||
&.active {
|
||||
a {
|
||||
background:#eee;
|
||||
background: #eee;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
&:last-child{
|
||||
&:first-child{
|
||||
a {
|
||||
border-right: none;
|
||||
border-left: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ul li a {
|
||||
border: none;
|
||||
}
|
||||
|
||||
form {
|
||||
padding: 10px;
|
||||
text-align: left;
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
small {
|
||||
margin-top: 10px;
|
||||
border-top: solid 1px #CCC;
|
||||
display: block;
|
||||
clear: both;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
const ENV = process.env['NODE_ENV'];
|
||||
|
||||
if (ENV !== 'test' && ENV !== 'travis') {
|
||||
console.log('Tests must be run with NODE_ENV=test');
|
||||
console.log('Also ensure that CSOL_DB_NAME is set to the test database');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (!process.env['CSOL_DB_NAME']) {
|
||||
console.log('No test database name set, defaulting to "test_csol"');
|
||||
process.env['CSOL_DB_NAME'] = 'test_csol';
|
||||
}
|
||||
|
||||
|
||||
const path = require('path');
|
||||
const async = require('async');
|
||||
|
||||
/**
|
||||
* Prepare the database by syncing all known models and optionally
|
||||
* saving some test data.
|
||||
*
|
||||
* If only one argument is passed, it is treated as the callback. When
|
||||
* there are no fixtures passed, the only tables that will get synced
|
||||
* are those that are known about (through `require`ing the models in
|
||||
* in the test file) before `prepare` is called.
|
||||
*
|
||||
* @param fixtures Array of fixture objects. A fixture object is
|
||||
* expected to have the following properties:
|
||||
* - model: Name of the model. Should correspond to a filein models/ dir
|
||||
* - name: Name to give the resulting instance
|
||||
* - values: Object with the values to save
|
||||
*/
|
||||
exports.prepare = function (fixtures, callback) {
|
||||
if (typeof fixtures == 'function')
|
||||
callback = fixtures, fixtures = [];
|
||||
|
||||
const db = require('../db');
|
||||
|
||||
const models = fixtures.reduce(function (models, fixture) {
|
||||
const filename = fixture.model.toLowerCase();
|
||||
models[fixture.model] = requireModel(filename);
|
||||
return models;
|
||||
}, {});
|
||||
|
||||
const save = saveFixture.bind(null, models);
|
||||
|
||||
db.sync({force: true})
|
||||
.success(function () {
|
||||
async.mapSeries(fixtures, save, function (err, instances) {
|
||||
if (err) throw err;
|
||||
instances.forEach(function (instance, idx) {
|
||||
const name = fixtures[idx].name;
|
||||
if (name)
|
||||
instances[name] = instance;
|
||||
});
|
||||
return callback(instances);
|
||||
});
|
||||
})
|
||||
.error(function (error) {
|
||||
console.log('Could not sync database models:');
|
||||
console.dir(error);
|
||||
process.exit(1);
|
||||
});
|
||||
};
|
||||
|
||||
function requireModel (filename) {
|
||||
return require(path.join(__dirname, '..', 'models', filename));
|
||||
}
|
||||
|
||||
function saveFixture(models, fixture, callback) {
|
||||
const Model = models[fixture.model];
|
||||
Model.create(fixture.values)
|
||||
.success(function (instance) {
|
||||
console.log('success');
|
||||
return callback(null, instance);
|
||||
})
|
||||
.error(function (error) {
|
||||
return callback(error);
|
||||
});
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
const $ = require('./');
|
||||
const test = require('tap').test;
|
||||
const Organization = require('../models/organization');
|
||||
|
||||
$.prepare([
|
||||
{ model: 'Organization',
|
||||
name: 'wbez',
|
||||
values: {
|
||||
id: 10,
|
||||
name: 'WBEZ 91.5',
|
||||
description: 'Chicago Public Radio',
|
||||
url: 'http://www.wbez.org/',
|
||||
imageUrl: 'https://twimg0-a.akamaihd.net/profile_images/858641792/WBEZ915_LOGO.jpg',
|
||||
address: '848 East Grand Ave, Navy Pier, Chicago, Illinois 60611',
|
||||
phone: '312.948.4600',
|
||||
email: 'admin@wbez.org'
|
||||
}
|
||||
}
|
||||
], function (fixtures) {
|
||||
test('Finding an organization', function (t) {
|
||||
const expect = fixtures['wbez'];
|
||||
Organization.find(expect.id).success(function (instance) {
|
||||
t.same(instance.rawAttributes, expect.rawAttributes);
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
});
|
|
@ -17,16 +17,46 @@
|
|||
<h1><a href="/">Chicago Summer of Learning</a></h1>
|
||||
<nav id="navigation">
|
||||
<ul class="nav nav-pills">
|
||||
<li class="programs{% if navItem == 'programs' %} active{% endif %}"><a href="/programs">Programs</a></li>
|
||||
<li class="orgs{% if navItem == 'orgs' %} active{% endif %}"><a href="/orgs">Organisations</a></li>
|
||||
<li class="claim{% if navItem == 'claim' %} active{% endif %}"><a href="/claim">Claim</a></li>
|
||||
<li class="learn{% if navItem == 'learn' %} active{% endif %}">
|
||||
<a href="/learn">Learn</a>
|
||||
</li>
|
||||
<li class="badges{% if navItem == 'badges' %} active{% endif %}">
|
||||
<a href="/badges">Badges</a>
|
||||
</li>
|
||||
<li class="challenges{% if navItem == 'challenges' %} active{% endif %}">
|
||||
<a href="/challenges">Challenges</a>
|
||||
</li>
|
||||
{% if user %}
|
||||
<li class="backpack{% if navItem == 'backpack' %} active{% endif %}"><a href="/backpack">My Badges</a></li>
|
||||
<li class="bookmarks{% if navItem == 'bookmarks' %} active{% endif %}"><a href="/favorites">My Favorites</a></li>
|
||||
<li class="log-out"><a href="/logout">Log Out</a></li>
|
||||
<li class="dropdown dashboard{% if navItem == 'dashboard' %} active{% endif %}">
|
||||
<a href="/dashboard" class="dropdown-toggle" role="button" data-toggle="dropdown" id="dashboard-menu-toggle">My Dashboard <i class="caret"></i></a>
|
||||
<ul class="dropdown-menu" role="menu" id="dashboard-menu" aria-labelledby="dashboard-menu-toggle">
|
||||
<li role="presentation"{% if subNavItem == 'badges' %} class="active"{% endif %}>
|
||||
<a role="menuitem" tabindex="-1" href="/dashboard/badges">My Badges</a>
|
||||
</li>
|
||||
<li role="presentation"{% if subNavItem == 'badges' %} class="active"{% endif %}>
|
||||
<a role="menuitem" tabindex="-1" href="/dashboard/favorites">My Favorites</a>
|
||||
</li>
|
||||
<li role="presentation"{% if subNavItem == 'badges' %} class="active"{% endif %}>
|
||||
<a role="menuitem" tabindex="-1" href="/dashboard/applications">My Applications</a>
|
||||
</li>
|
||||
<li class="divider" role="presentation" aria-hidden="true"></li>
|
||||
<li role="presentation">
|
||||
<a role="menuitem" tabindex="-1" href="/logout">Log Out</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
{% else %}
|
||||
<li class="log-in{% if navItem == 'log-in' %} active{% endif %}"><a href="/login">Log In</a></li>
|
||||
<li class="sign-up{% if navItem == 'sign-up' %} active{% endif %}"><a href="/signup">Sign Up</a></li>
|
||||
<li class="dropdown log-in{% if navItem == 'log-in' %} active{% endif %}">
|
||||
<a href="/login" class="dropdown-toggle" role="button" data-toggle="dropdown" id="menu-login-form-toggle">Log In / Sign Up <i class="caret"></i></a>
|
||||
<form class="dropdown-menu" id="menu-login-form" aria-label="Log In" method="post" action="/login">
|
||||
<label for="menu-login-username">Email or username:</label>
|
||||
<input type="text" id="menu-login-username" name="username" placeholder="e.g. user@example.com">
|
||||
<label for="menu-login-password">Password:</label>
|
||||
<input type="password" id="menu-login-password" name="password">
|
||||
<button type="submit" class="btn">Submit</button>
|
||||
<small>Don't have an account? <a href="/signup">Sign up.</a></small>
|
||||
</form>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</nav>
|
||||
|
@ -72,5 +102,7 @@
|
|||
</div><!-- .row-fluid -->
|
||||
</div>
|
||||
</footer>
|
||||
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
|
||||
<script src="/media/bootstrap/js/bootstrap.js"></script>
|
||||
</body>
|
||||
</html>
|
Загрузка…
Ссылка в новой задаче