diff --git a/.travis.yml b/.travis.yml index cf81c325c..f11973cb1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,7 +17,7 @@ env: - SKIP_CLEANUP=true - BUILD_ARCHIVE=$TRAVIS_BUILD_ID.zip before_deploy: -- zip -r $BUILD_ARCHIVE . +- zip -qr $BUILD_ARCHIVE . deploy: - provider: elasticbeanstalk access_key_id: $EB_AWS_ACCESS_KEY_ID diff --git a/en.json b/en.json index b8a25b811..19a2f7f1a 100644 --- a/en.json +++ b/en.json @@ -14,6 +14,7 @@ "general.forParents": "For Parents", "general.forEducators": "For Educators", "general.guidelines": "Community Guidelines", + "general.help": "Help", "general.jobs": "Jobs", "general.joinScratch": "Join Scratch", "general.legal": "Legal", @@ -27,11 +28,13 @@ "general.scratchEd": "ScratchEd", "general.scratchFoundation": "Scratch Foundation", "general.scratchJr": "ScratchJr", + "general.search": "Search", "general.signIn": "Sign in", "general.statistics": "Statistics", "general.support": "Support", "general.termsOfUse": "Terms of Use", "general.username": "Username", + "general.viewAll": "View All", "general.whatsHappening": "What's Happening?", "general.wiki": "Scratch Wiki", "footer.about": "About Scratch", @@ -47,6 +50,7 @@ "intro.tryItOut": "TRY IT OUT", "login.forgotPassword": "Forgot Password?", "navigation.signOut": "Sign out", + "news.scratchNews": "Scratch News", "parents.FaqAgeRangeA": "While Scratch is primarily designed for 8 to 16 year olds, it is also used by people of all ages, including younger children with their parents.", "parents.FaqAgeRangeQ": "What is the age range for Scratch?", "parents.FaqResourcesQ": "What resources are available for learning Scratch?", diff --git a/server/config.js b/server/config.js index a11cf8bd2..393219278 100644 --- a/server/config.js +++ b/server/config.js @@ -7,11 +7,14 @@ module.exports = { 'and animations.', // Open graph - og_image: 'https://scratch.mit.edu/images/og_image.jpg', - og_image_type: 'image/jpeg', + og_image: 'https://scratch.mit.edu/images/scratch-og.png', + og_image_type: 'image/png', og_image_width: 986, og_image_height: 860, // Analytics & Monitoring - ga_tracker: process.env.GA_TRACKER || '' + ga_tracker: process.env.GA_TRACKER || '', + + // Use minified JS libraries + min: (process.env.NODE_ENV === 'production') ? '.min' : '' }; diff --git a/server/index.js b/server/index.js index 954769e13..e206d2955 100644 --- a/server/index.js +++ b/server/index.js @@ -13,9 +13,23 @@ var log = require('./log'); var proxies = require('./proxies.json'); var routes = require('./routes.json'); -// Server setup +// Create server var app = express(); app.disable('x-powered-by'); + +// Block POST & PUT requests in production +if (process.env.NODE_ENV === 'production') { + app.use(function (req, res, next) { + if (req.method === 'GET') return next(); + if (req.method === 'OPTIONS') return next(); + if (req.method === 'HEAD') return next(); + + res.writeHead(405, {'content-type' : 'application/json'}); + res.end('{"error": "Method not allowed"}'); + }); +} + +// Server setup app.use(log()); app.use(compression()); app.use(express.static(path.resolve(__dirname, '../build'), { diff --git a/server/proxies.json b/server/proxies.json index ffff8ca4c..4298ae271 100644 --- a/server/proxies.json +++ b/server/proxies.json @@ -6,6 +6,7 @@ "/i18n/setlang/", "/login_retry/", "/media/", + "/scratch_admin/homepage/clear-cache/", "/session/", "/site-api", "/static/" diff --git a/server/template.html b/server/template.html index b2c0452f7..6102ec4bf 100644 --- a/server/template.html +++ b/server/template.html @@ -41,8 +41,8 @@ - - + + @@ -59,7 +59,5 @@ }); ga('send', 'pageview'); - - diff --git a/src/components/adminpanel/adminpanel.scss b/src/components/adminpanel/adminpanel.scss index ab1c7fa4e..64ef709a0 100644 --- a/src/components/adminpanel/adminpanel.scss +++ b/src/components/adminpanel/adminpanel.scss @@ -58,8 +58,12 @@ justify-content: space-between; .button { - background-color: $ui-dark-gray; padding: .5rem 1rem; + + &.inprogress { + background-color: $ui-dark-gray; + color: $type-gray; + } } } } diff --git a/src/components/banner/banner.scss b/src/components/banner/banner.scss index 4164171e2..2596df6c8 100644 --- a/src/components/banner/banner.scss +++ b/src/components/banner/banner.scss @@ -5,7 +5,7 @@ $navigation-height: 50px; .banner { position: fixed; top: $navigation-height; - z-index: 99; + z-index: 9; box-shadow: 0 1px 1px $ui-dark-gray; background-color: $ui-orange; width: 100%; diff --git a/src/components/forms/button.scss b/src/components/forms/button.scss index 3f0cc4fba..c91976c1d 100644 --- a/src/components/forms/button.scss +++ b/src/components/forms/button.scss @@ -1,6 +1,8 @@ @import "../../colors"; $base-bg: $ui-white; +$fail-bg: $ui-orange; +$pass-bg: $ui-aqua; .button { display: inline-block; @@ -15,12 +17,7 @@ $base-bg: $ui-white; font-size: .8rem; font-weight: bold; - &.white { - border-top: 1px inset $active-gray; - background-color: $base-bg; - color: $ui-blue; - } - + /* USER BUTTON STATES */ &:hover { box-shadow: 0 2px 2px $box-shadow-gray; } @@ -32,4 +29,23 @@ $base-bg: $ui-white; &:focus { outline: none; } + + /* DATA BUTTON STATES */ + &.white { + border-top: 1px inset $active-gray; + background-color: $base-bg; + color: $ui-blue; + } + + &.pass { + background-color: $pass-bg; + } + + &.fail { + background-color: $fail-bg; + } + + &:disabled { + box-shadow: none; + } } diff --git a/src/components/navigation/navigation.jsx b/src/components/navigation/navigation.jsx index d88701e5f..9e83dc6df 100644 --- a/src/components/navigation/navigation.jsx +++ b/src/components/navigation/navigation.jsx @@ -28,6 +28,10 @@ var defaultMessages = defineMessages({ myStuff: { id: 'general.myStuff', defaultMessage: 'My Stuff' + }, + search: { + id: 'general.search', + defaultMessage: 'Search' } }); @@ -222,7 +226,7 @@ var Navigation = React.createClass({
  • - +
    diff --git a/src/main.scss b/src/main.scss index a7889cd29..78840ed01 100644 --- a/src/main.scss +++ b/src/main.scss @@ -68,10 +68,12 @@ a:hover { } #view { + display: inline-block; + /* NOTE: Margin should match height in navigation.scss */ margin-top: 50px; background-color: $background-color; - - padding: 20px 0; + padding: 20px 1px; + min-width: 100%; min-height: 768px; } diff --git a/src/views/splash/splash.jsx b/src/views/splash/splash.jsx index e7071a042..345a6e0e6 100644 --- a/src/views/splash/splash.jsx +++ b/src/views/splash/splash.jsx @@ -32,7 +32,8 @@ var Splash = injectIntl(React.createClass({ news: [], featuredCustom: {}, featuredGlobal: {}, - showEmailConfirmationModal: false + showEmailConfirmationModal: false, + refreshCacheStatus: 'notrequested' }; }, componentDidUpdate: function (prevProps, prevState) { @@ -115,6 +116,36 @@ var Splash = injectIntl(React.createClass({ if (!err) this.setState({projectCount: body.count}); }.bind(this)); }, + refreshHomepageCache: function () { + this.api({ + host: '', + uri: '/scratch_admin/homepage/clear-cache/', + method: 'post', + useCsrf: true + }, function (err, body) { + if (err) return this.setState({refreshCacheStatus: 'fail'}); + if (!body.success) return this.setState({refreshCacheStatus: 'inprogress'}); + return this.setState({refreshCacheStatus: 'pass'}); + }.bind(this)); + }, + getHomepageRefreshStatus: function () { + var status = { + status: this.state.refreshCacheStatus, + disabled: false, + content: 'Refresh' + }; + if (this.state.refreshCacheStatus === 'inprogress') { + status.disabled = true; + status.content = 'In Progress'; + } else if (this.state.refreshCacheStatus === 'pass') { + status.disabled = true; + status.content = 'Requested'; + } else if (this.state.refreshCacheStatus == 'fail') { + status.disabled = false; + status.content = 'Error'; + } + return status; + }, showEmailConfirmationModal: function () { this.setState({emailConfirmationModalOpen: true}); }, @@ -286,6 +317,7 @@ var Splash = injectIntl(React.createClass({ render: function () { var featured = this.renderHomepageRows(); var emailConfirmationStyle = {width: 500, height: 330, padding: 1}; + var homepageCacheState = this.getHomepageRefreshStatus(); return (
    {this.shouldShowEmailConfirmation() ? [ @@ -340,18 +372,14 @@ var Splash = injectIntl(React.createClass({
    • -
      - -
      - Refresh row data: - -
      -
      +
      + Refresh row data: + +
    diff --git a/static/images/og_image.jpg b/static/images/og_image.jpg deleted file mode 100644 index 4c69a767f..000000000 Binary files a/static/images/og_image.jpg and /dev/null differ diff --git a/static/images/scratch-og.png b/static/images/scratch-og.png new file mode 100644 index 000000000..bf5097069 Binary files /dev/null and b/static/images/scratch-og.png differ