diff --git a/client/imports/ui/components/mdeditor/mdeditor.ts b/client/imports/ui/components/mdeditor/mdeditor.ts index 8c17ffe6..15428f16 100644 --- a/client/imports/ui/components/mdeditor/mdeditor.ts +++ b/client/imports/ui/components/mdeditor/mdeditor.ts @@ -29,7 +29,7 @@ ngAfterViewInit(){ var self = this; // Instantiate SimpleMDE - this.mde = new SimpleMDE({ element: this.elementRef.nativeElement.value }); + this.mde = new SimpleMDE({ element: this.textarea.nativeElement }); // Read initial data from task markdown this.mde.value(self.mdData); // Catch changes diff --git a/client/imports/ui/pages/course/course.html b/client/imports/ui/pages/course/course.html index b5f2b45e..af2cae0b 100644 --- a/client/imports/ui/pages/course/course.html +++ b/client/imports/ui/pages/course/course.html @@ -9,6 +9,7 @@ Labs Grades Students + Upload @@ -17,7 +18,8 @@ {{ courseNumber }} Home Labs Grades - Students + Students + Upload diff --git a/client/imports/ui/pages/course/course.ts b/client/imports/ui/pages/course/course.ts index 1ae23984..df6e5eb7 100644 --- a/client/imports/ui/pages/course/course.ts +++ b/client/imports/ui/pages/course/course.ts @@ -41,7 +41,9 @@ this.subscribe('user-courses', () => { this.autorun(() => { - this.courseNumber = Collections.courses.findOne({ _id: this.courseId }).course_number; + if(typeof Collections.courses.findOne({ _id: this.courseId }) !== "undefined") { + this.courseNumber = Collections.courses.findOne({ _id: this.courseId }).course_number; + } }); }, true); } diff --git a/client/imports/ui/pages/dashboard/dashboard.html b/client/imports/ui/pages/dashboard/dashboard.html index bc4d5d51..04c6e0c3 100644 --- a/client/imports/ui/pages/dashboard/dashboard.html +++ b/client/imports/ui/pages/dashboard/dashboard.html @@ -62,13 +62,51 @@ -
- - -

Welcome to TuxLab!

-
- - - -
-
+
+ + +
+ +
+ + +
+
+

About TuxLab

+

+ TuxLab is an opensource platform for creating interactive Linux courses. + Click on the link below to read more about TuxLab! + Come back if you like what you see, go away if you do not. + Scroll down to browse some of the available courses on the site! +

+ +
+
+ + +
+
+

Explore Courses

+

+ These are some courses that you will be able to enroll + in once you have registered. +

+
+ +
+ +
+
+ +
\ No newline at end of file diff --git a/client/imports/ui/pages/dashboard/dashboard.ts b/client/imports/ui/pages/dashboard/dashboard.ts index 251a8fdf..e6db27d9 100644 --- a/client/imports/ui/pages/dashboard/dashboard.ts +++ b/client/imports/ui/pages/dashboard/dashboard.ts @@ -15,30 +15,38 @@ import { courses } from '../../../../../collections/courses.ts'; import { course_records } from '../../../../../collections/course_records.ts'; +// Explore + import { ExploreView } from '../../components/explore/explore.ts'; + +// Login + import Login from '../account/login.ts'; + // Define Dashboard Component @Component({ - selector: 'tuxlab-dashboard', - templateUrl: '/client/imports/ui/pages/dashboard/dashboard.html', - directives: [ - MATERIAL_DIRECTIVES, - MD_SIDENAV_DIRECTIVES, - ROUTER_DIRECTIVES - ] + selector: 'tuxlab-dashboard', + templateUrl: '/client/imports/ui/pages/dashboard/dashboard.html', + directives: [ + MATERIAL_DIRECTIVES, + MD_SIDENAV_DIRECTIVES, + ROUTER_DIRECTIVES, + Login, + ExploreView + ] }) // Export Dashboard Class @InjectUser('user') export default class Dashboard extends MeteorComponent { - user : Meteor.User; + user : Meteor.User; private courses = []; private grades = []; constructor() { super(); - this.subscribe('user-courses', () => { - this.courses = courses.find({}, { limit: 5 }).fetch(); - }, true); + this.subscribe('user-courses', () => { + this.courses = courses.find({}, { limit: 5 }).fetch(); + }, true); this.subscribe('course-records', () => { let records = course_records.find().fetch(); for(let i = 0; i < records.length; i++) { diff --git a/client/imports/ui/pages/lab/labcreate.ts b/client/imports/ui/pages/lab/labcreate.ts index 004cf100..a622f41a 100644 --- a/client/imports/ui/pages/lab/labcreate.ts +++ b/client/imports/ui/pages/lab/labcreate.ts @@ -46,6 +46,8 @@ export default class LabCreate extends MeteorComponent { this.lab.file = ""; this.uploaded = false; this.output = "Compiling... Errors will display below."; + + document.getElementById('course-content').style.maxWidth = "100%"; } /* UPLOAD HANDLER */ diff --git a/client/imports/ui/routes/course.routes.ts b/client/imports/ui/routes/course.routes.ts index d30d3ac2..b38a1cd5 100644 --- a/client/imports/ui/routes/course.routes.ts +++ b/client/imports/ui/routes/course.routes.ts @@ -12,6 +12,7 @@ import { GradeList } from '../pages/course/gradelist.ts'; import { LabList } from '../pages/course/lablist.ts'; import { CourseDashboard } from '../pages/course/course_dashboard.ts'; import { GradeView } from '../pages/course/gradeview.ts'; +import LabCreate from '../pages/lab/labcreate.ts' import LabView from '../pages/lab/labview.ts'; export const courseRoutes: RouterConfig = [ @@ -23,7 +24,8 @@ export const courseRoutes: RouterConfig = [ { path: 'grades', component: GradeList }, { path: 'labs', component: LabList }, { path: 'labs/:labid', canActivate: [ GuardAuth, CourseGuardRecord ], component: LabView }, - { path: 'grades/:gradeid', canActivate: [ GuardAuth ], component: GradeView } + { path: 'grades/:gradeid', canActivate: [ GuardAuth ], component: GradeView }, + { path: 'lab-create', component: LabCreate } // { path: 'users', as: 'UserList', component: UserList }, // { path: 'user/:userid', as: 'UserView', component: UserView }, // { path: 'labs', as: 'LabList', component: LabList }, diff --git a/client/imports/ui/routes/routes.ts b/client/imports/ui/routes/routes.ts index dbead183..da2bdea5 100644 --- a/client/imports/ui/routes/routes.ts +++ b/client/imports/ui/routes/routes.ts @@ -14,9 +14,6 @@ import { provideRouter, RouterConfig } from '@angular/router'; // Error import ErrorPage from '../pages/error/error.ts' - // Lab - import LabCreate from '../pages/lab/labcreate.ts' - // Course import { courseRoutes } from './course.routes.ts'; import { CourseGuardRecord } from './course.guard.record.ts'; @@ -40,7 +37,6 @@ const routes : RouterConfig = [ { path: 'login', component: Login }, { path: 'terms', component: Terms }, { path: 'privacy', component: Privacy }, - { path: 'lab-create', component: LabCreate }, { path: 'explore', component: Explore }, { path: 'courses', component: CourseList }, { path: 'error/:code', component: ErrorPage }, diff --git a/client/style/dashboard/_dashboard.scss b/client/style/dashboard/_dashboard.scss index 52e54932..ba60e5b5 100644 --- a/client/style/dashboard/_dashboard.scss +++ b/client/style/dashboard/_dashboard.scss @@ -63,3 +63,67 @@ } } } + +.tuxlab-dashboard-nonuser { + .login-section { + background-image: $university-splash-image; + background-repeat: no-repeat; + background-size: cover; + box-shadow: inset 0 0 0 1000px rgba(0, 0, 0, 0.5); + height: 55vh; + padding-top: 15vh; + .login-wrapper { + max-width: $tuxlab-max-width; + margin: 0 auto; + .login-card { + width: 500px; + margin:0; + h1 { + color: #e5e5e6; + font-family: "Open Sans"; + font-weight: 300; + font-size: 46px; + text-align: center; + } + md-card { + margin: 0; + background-color: rgba(255, 255, 255, 0.6); + md-card-content { + margin: 0; + padding: 0; + } + } + .tuxlab-login { + height: 250px; + } + } + } + } + .section-text { + h1 { + color: #444444; + font-family: "Open Sans"; + font-weight: 300; + font-size: 46px; + padding: 15px; + } + .button-wrapper { + margin-top: 20px; + margin-bottom: 15px; + text-align: center; + a { + color: white; + background-color: #4fafef; + } + } + } + .about-section { + background-color: white; + padding: 15px; + @extend .section-text; + } + .courses-section { + padding: 15px; + @extend .section-text; + } +} \ No newline at end of file diff --git a/client/style/explore/_explore.scss b/client/style/explore/_explore.scss index b5994aa3..5d0b32bb 100644 --- a/client/style/explore/_explore.scss +++ b/client/style/explore/_explore.scss @@ -2,21 +2,6 @@ width:100%; max-width:$tuxlab-max-width; margin:0 auto; - - md-tab-group { - background-color: white; - margin: 30px; - .md-active.md-tab-label { - background-color: #ffd54f; - } - md-ink-bar { - background-color: white; - } - } - .md-tab-header { - background-color: #ffc400; - } - #search-view { display: none; } @@ -143,4 +128,17 @@ float: left; } } + md-tab-group { + background-color: white; + margin: 30px; + .md-active.md-tab-label { + background-color: #ffd54f; + } + md-ink-bar { + background-color: white; + } + } + .md-tab-header { + background-color: #ffc400; + } } \ No newline at end of file diff --git a/client/style/theme/_cmu.scss b/client/style/theme/_cmu.scss index 47bdbfa6..f968fd88 100644 --- a/client/style/theme/_cmu.scss +++ b/client/style/theme/_cmu.scss @@ -7,4 +7,5 @@ $primary-color-dark: #960e24; // Images $university_logo : url("https://upload.wikimedia.org/wikipedia/commons/thumb/9/9b/Carnegie_Mellon_wordmark.svg/2000px-Carnegie_Mellon_wordmark.svg.png"); $university_picture: url("http://engineering.cmu.edu/files/images/maker-wing/hamerschlag-large.jpg"); +$university_splash_image : url('http://www.asergeev.com/pictures/archives/2013/1212/jpeg/12.jpg'); $err_image : url("http://i.imgur.com/qI1CIwp.gif"); diff --git a/client/tuxlab.html b/client/tuxlab.html index 6331f6ca..3fe149d0 100644 --- a/client/tuxlab.html +++ b/client/tuxlab.html @@ -16,7 +16,7 @@ Announcements - + Terminal diff --git a/client/tuxlab.ts b/client/tuxlab.ts index 41e54e92..70d932e2 100644 --- a/client/tuxlab.ts +++ b/client/tuxlab.ts @@ -1,58 +1,75 @@ /* TuxLab - TuxLab.ts */ // Meteor Imports - import { Meteor } from 'meteor/meteor'; - import { Mongo } from 'meteor/mongo'; - import 'reflect-metadata'; - import 'zone.js/dist/zone'; - import './startup.js'; + import { Meteor } from 'meteor/meteor'; + import { Mongo } from 'meteor/mongo'; + import 'reflect-metadata'; + import 'zone.js/dist/zone'; + import './startup.js'; // Angular Imports - import { MeteorComponent } from 'angular2-meteor'; - import { Component, ViewEncapsulation, provide, PLATFORM_DIRECTIVES} from '@angular/core'; - import { APP_BASE_HREF, CORE_DIRECTIVES } from '@angular/common'; - import { HTTP_PROVIDERS } from '@angular/http'; - import { bootstrap } from '@angular/platform-browser-dynamic'; - import { InjectUser } from 'angular2-meteor-accounts-ui'; + import { MeteorComponent } from 'angular2-meteor'; + import { Component, ViewEncapsulation, provide, PLATFORM_DIRECTIVES} from '@angular/core'; + import { APP_BASE_HREF, CORE_DIRECTIVES } from '@angular/common'; + import { HTTP_PROVIDERS } from '@angular/http'; + import { bootstrap } from '@angular/platform-browser-dynamic'; + import { InjectUser } from 'angular2-meteor-accounts-ui'; // Angular Material Imports - import { MATERIAL_PROVIDERS, MATERIAL_DIRECTIVES } from 'ng2-material'; - import { ResponsiveState, RESPONSIVE_DIRECTIVES } from 'responsive-directives-angular2'; - import { disableDeprecatedForms, provideForms } from '@angular/forms'; - import { MD_ICON_DIRECTIVES, MdIconRegistry } from '@angular2-material/icon' - import { MD_SIDENAV_DIRECTIVES } from '@angular2-material/sidenav'; - import { MD_TOOLBAR_DIRECTIVES } from '@angular2-material/toolbar'; + import { MATERIAL_PROVIDERS, MATERIAL_DIRECTIVES } from 'ng2-material'; + import { ResponsiveState, RESPONSIVE_DIRECTIVES } from 'responsive-directives-angular2'; + import { disableDeprecatedForms, provideForms } from '@angular/forms'; + import { MD_ICON_DIRECTIVES, MdIconRegistry } from '@angular2-material/icon' + import { MD_SIDENAV_DIRECTIVES } from '@angular2-material/sidenav'; + import { MD_TOOLBAR_DIRECTIVES } from '@angular2-material/toolbar'; // Routes - import { ROUTER_DIRECTIVES, RouterConfig, Router } from '@angular/router'; - import { ROUTE_PROVIDERS } from './imports/ui/routes/routes.ts' + import { ROUTER_DIRECTIVES, RouterConfig, Router } from '@angular/router'; + import { ROUTE_PROVIDERS } from './imports/ui/routes/routes.ts' // Define TuxLab Component @Component({ - selector: 'tuxlab', - templateUrl: '/client/tuxlab.html', - directives: [ ROUTER_DIRECTIVES, - MATERIAL_DIRECTIVES, - MD_TOOLBAR_DIRECTIVES, - MD_ICON_DIRECTIVES, - MD_SIDENAV_DIRECTIVES - ], - viewProviders: [MdIconRegistry] + selector: 'tuxlab', + templateUrl: '/client/tuxlab.html', + directives: [ + ROUTER_DIRECTIVES, + MATERIAL_DIRECTIVES, + MD_TOOLBAR_DIRECTIVES, + MD_ICON_DIRECTIVES, + MD_SIDENAV_DIRECTIVES + ], + viewProviders: [MdIconRegistry] }) @InjectUser('user') class TuxLab extends MeteorComponent { - user: Meteor.User; - constructor(mdIconRegistry: MdIconRegistry, private router: Router) { - super(); - // Create Icon Font - mdIconRegistry.registerFontClassAlias('tux', 'tuxicon'); - mdIconRegistry.setDefaultFontSetClass('tuxicon'); - } - tuxLogout() { - Meteor.logout(); - this.router.navigate(['/']); - } + user: Meteor.User; + lastLabId: string; + lastCourseId: string; + + constructor(mdIconRegistry: MdIconRegistry, private router: Router) { + super(); + // Create Icon Font + mdIconRegistry.registerFontClassAlias('tux', 'tuxicon'); + mdIconRegistry.setDefaultFontSetClass('tuxicon'); + } + + tuxLogout() { + Meteor.logout(); + this.router.navigate(['/']); + } + + toLastLab() { + var self = this; + Meteor.call('getLastLab', function(err, res) { + if (err) { + self.router.navigate(['/']); + } + else { + self.router.navigate(['/course/' + res.courseId + '/labs/' + res.labId]); + } + }); + } } bootstrap(TuxLab, [ diff --git a/server/imports/lab/methods.ts b/server/imports/lab/methods.ts index a7c515f6..ad09c102 100644 --- a/server/imports/lab/methods.ts +++ b/server/imports/lab/methods.ts @@ -14,7 +14,7 @@ import{ prepLab, next, verify } from './labMethods.ts'; import{ markdown_editor } from './export_markdown.ts'; Meteor.methods({ - + /**prepareLab: prepares a labExec object for the current user * takes the id of the lab and a callback as parameter * callback: (err,pass) @@ -24,7 +24,7 @@ Meteor.methods({ TuxLog.log("trace","preparing lab"); - Meteor.user().sessions.push({labId: labId,started: Date.now()}); + // Meteor.user().sessions.push({labId: labId,started: Date.now()}); // Collections.users.update({_id: Meteor.userId()},{$set:{sessions: this.user.sessions}}); //get course Id @@ -53,7 +53,7 @@ Meteor.methods({ //get user nick var uId = Meteor.user().profile.nickname; - + //wrap sync functions var verifyAsync = Meteor.wrapAsync(verify); @@ -81,7 +81,7 @@ Meteor.methods({ var courseId = Collections.labs.findOne({_id: labId}).course_id; //wrap sync functions var nextAsync = Meteor.wrapAsync(next); - + try{ var res = nextAsync(uId,labId,courseId); return res; @@ -105,22 +105,22 @@ Meteor.methods({ SessionCache.get(uId,labId,function(err,res){ if(err){ TuxLog.log("warn",err); - throw new Meteor.Error("Internal Service Error"); + throw new Meteor.Error("Internal Service Error"); } else if(!res){ TuxLog.log("warn",new Meteor.Error("SessionCache.get failed to return a session instance")); - throw new Meteor.Error("Internal Service Error"); + throw new Meteor.Error("Internal Service Error"); } else{ var endAsync = Meteor.wrapAsync(res.end,res); - try{ - var result = endAsync(); - return "success" //TODO: @Derek what to return here? - } - catch(e){ - TuxLog.log("warn",e); - throw new Meteor.Error("Internal Service Error"); - } + try{ + var result = endAsync(); + return "success" //TODO: @Derek what to return here? + } + catch(e){ + TuxLog.log("warn",e); + throw new Meteor.Error("Internal Service Error"); + } } }); }, diff --git a/server/imports/startup/docker.js b/server/imports/startup/docker.js index ee466379..b08df197 100644 --- a/server/imports/startup/docker.js +++ b/server/imports/startup/docker.js @@ -3,9 +3,9 @@ var fs = require('fs'); var dockerode_options = { host: nconf.get('swarm_node_ip'), - port: nconf.get('swarm_node_port'), - ca: fs.readFileSync(nconf.get('swarm_cert_dir')+"/ca.pem"), - cert: fs.readFileSync(nconf.get('swarm_cert_dir')+"/cert.pem"), - key: fs.readFileSync(nconf.get('swarm_cert_dir')+"/key.pem") + port: nconf.get('swarm_node_port')//, + // ca: fs.readFileSync(nconf.get('swarm_cert_dir')+"/ca.pem"), + // cert: fs.readFileSync(nconf.get('swarm_cert_dir')+"/cert.pem"), + //key: fs.readFileSync(nconf.get('swarm_cert_dir')+"/key.pem") }; docker = new dockerode(dockerode_options); diff --git a/tsconfig.json b/tsconfig.json index ef0803c5..5d798445 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -56,6 +56,7 @@ "server/imports/course/methods.ts", "server/imports/course/search.ts", "server/imports/lab/checkLab.d.ts", + "server/imports/lab/export_markdown.ts", "server/imports/lab/labMethods.ts", "server/imports/lab/markdown.ts", "server/imports/lab/methods.ts",