├── db_templates ├── Python-UnitTest │ └── Root │ │ ├── __init__.py │ │ ├── src │ │ ├── __init__.py │ │ ├── main.py │ │ └── finder.py │ │ ├── test │ │ ├── __init__.py │ │ └── finderTest.py │ │ ├── testSubmission │ │ ├── __init__.py │ │ └── subTest.py │ │ └── codeboard.json ├── Python │ └── Root │ │ ├── main.py │ │ └── codeboard.json ├── Haskell │ └── Root │ │ ├── Main.hs │ │ └── codeboard.json ├── C++ │ └── Root │ │ └── main.cpp ├── C │ └── Root │ │ └── main.c ├── Java │ └── Root │ │ ├── Main.java │ │ └── codeboard.json ├── Haskell-HSpec │ └── Root │ │ ├── codeboard.json │ │ ├── Src │ │ ├── Finder.hs │ │ └── Main.hs │ │ ├── Test │ │ └── FinderSpec.hs │ │ └── TestSubmission │ │ └── SubSpec.hs └── Java-JUnit │ └── Root │ ├── codeboard.json │ ├── src │ ├── Main.java │ └── Finder.java │ ├── test │ └── FinderTest.java │ └── test_submission │ └── SubTest.java ├── app ├── robots.txt ├── favicon.png ├── images │ ├── close_dark.png │ ├── close_light.png │ ├── logo │ │ ├── codeboard_logo_256.png │ │ └── codeboard_logo_50.png │ └── users │ │ └── defaults │ │ ├── smile1.png │ │ ├── smile2.png │ │ ├── smile3.png │ │ ├── smile4.png │ │ └── smile5.png ├── components │ ├── angularTreeview │ │ ├── img │ │ │ ├── file.png │ │ │ ├── folder.png │ │ │ ├── preview.png │ │ │ ├── jsfiddle01.png │ │ │ ├── jsfiddle02.png │ │ │ └── folder-closed.png │ │ ├── LICENSE │ │ ├── angular.treeview.min.js │ │ ├── css │ │ │ └── angular.treeview.css │ │ ├── README.md │ │ └── angular.treeview.js │ └── ngGrid │ │ └── ngGridHeight.js ├── styles │ ├── style.css │ ├── userSettings.css │ ├── projectSummary.css │ ├── projectListing.css │ ├── docs.css │ ├── projectStats.css │ ├── main.css │ └── ide.css ├── scripts │ ├── resources │ │ ├── sessionRes.js │ │ ├── userprojectRes.js │ │ ├── userRes.js │ │ └── projectRes.js │ ├── directives │ │ ├── ngEnter.js │ │ └── ngSelectOnFocus.js │ ├── controllers │ │ ├── usersAllCtrl.js │ │ ├── navbarCtrl.js │ │ ├── projectSummaryCtrl.js │ │ ├── main.js │ │ ├── signinCtrl.js │ │ ├── supportCtrl.js │ │ ├── userProjectsCtrl.js │ │ ├── projectSubmissionsCtrl.js │ │ ├── projectUserProjectsCtrl.js │ │ ├── projectNewCtrl.js │ │ ├── passwordResetCtrl.js │ │ └── signupCtrl.js │ └── services │ │ ├── userSrv.js │ │ ├── uploadService.js │ │ ├── websocketSrv.js │ │ └── ideSnippetsSrv.js └── views │ └── partials │ ├── 404.html │ ├── 401.html │ ├── navbar.html │ ├── usersAll.html │ ├── signin.html │ ├── supportLtiDebug.html │ ├── projectUserProjects.html │ ├── passwordReset.html │ ├── main.html │ ├── projectNew.html │ ├── projectSubmissions.html │ └── projectSummary.html ├── .bowerrc ├── lib ├── config │ ├── config.js │ ├── env │ │ ├── test.js │ │ ├── development.js │ │ ├── production.js │ │ └── all.js │ └── passport.js ├── .jshintrc ├── models │ ├── templateProject.js │ ├── file.js │ ├── ltiSession.js │ ├── templateFile.js │ ├── index.js │ ├── userProject.js │ ├── user.js │ ├── submission.js │ └── project.js ├── controllers │ ├── index.js │ ├── authenticationCtrl.js │ └── supportCtrl.js ├── services │ ├── userSrv.js │ ├── toolSrv.js │ ├── mailSrv.js │ ├── templateSrv.js │ └── mockmantraserver.js └── util.js ├── test └── server │ ├── src_examples │ ├── python │ │ ├── py_error_missing_setting.json │ │ ├── py_one_file.json │ │ ├── py_incremental1.json │ │ ├── py_wrong_id1.json │ │ ├── py_error_one_file.json │ │ ├── py_error_setting.json │ │ ├── py_run_invalid_id.json │ │ ├── py_error_incremental1.json │ │ ├── py_error_main.json │ │ ├── py_error_incremental2.json │ │ ├── py_error_several_files.json │ │ ├── py_incremental2.json │ │ ├── py_wrong_id2.json │ │ ├── py_several_files.json │ │ └── py_several_files_folder.json │ ├── c │ │ ├── c_wrong_id1.json │ │ ├── c_incremental1.json │ │ ├── c_error_incremental1.json │ │ ├── c_error_one_file.json │ │ ├── c_run_file.json │ │ ├── c_one_file.json │ │ ├── c_error_incremental2.json │ │ ├── c_error_main.json │ │ ├── c_wrong_id2.json │ │ ├── c_several_files.json │ │ ├── c_incremental2.json │ │ ├── c_run_several_files.json │ │ └── c_several_files_folders.json │ ├── cpp │ │ ├── cpp_wrong_id1.json │ │ ├── cpp_incremental1.json │ │ ├── cpp_error_incremental1.json │ │ ├── cpp_error_one_file.json │ │ ├── cpp_one_file.json │ │ ├── cpp_run_file.json │ │ ├── cpp_error_incremental2.json │ │ ├── cpp_error_main.json │ │ ├── cpp_several_files.json │ │ ├── cpp_incremental2.json │ │ ├── cpp_wrong_id2.json │ │ ├── cpp_run_several_files.json │ │ └── cpp_several_files_folders.json │ ├── haskell │ │ ├── hs_error_missing_setting.json │ │ ├── hs_incremental1.json │ │ ├── hs_one_file.json │ │ ├── hs_run_file.json │ │ ├── hs_wrong_id1.json │ │ ├── hs_error_one_file.json │ │ ├── hs_error_setting_file.json │ │ ├── hs_run_invalid_id.json │ │ ├── hs_error_main.json │ │ ├── hs_error_incremental1.json │ │ ├── hs_error_several_files.json │ │ ├── hs_wrong_id2.json │ │ ├── hs_incremental2.json │ │ ├── hs_several_files.json │ │ ├── hs_run_several_files.json │ │ ├── hs_several_files_folders.json │ │ └── hs_run_several_files_folder.json │ └── java │ │ ├── j_error_missing_setting.json │ │ ├── j_incremental1.json │ │ ├── j_wrong_id1.json │ │ ├── j_error_setting_file.json │ │ ├── j_error.json │ │ ├── j_one_file.json │ │ ├── j_run_file.json │ │ ├── j_run_invalid_id.json │ │ ├── j_no_main_specified.json │ │ ├── j_error_several_files.json │ │ ├── j_wrong_id2.json │ │ ├── j_incremental2.json │ │ ├── j_several_files.json │ │ ├── j_run_several_files.json │ │ ├── j_several_files_folders.json │ │ └── j_run_several_files_folder.json │ ├── init │ └── 0_initDB.js │ └── 06_testPartials.js ├── .gitignore ├── .jshintrc ├── LICENSE ├── bower.json ├── README.md ├── package.json └── karma.conf.js /db_templates/Python-UnitTest/Root/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /db_templates/Python-UnitTest/Root/src/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /db_templates/Python-UnitTest/Root/test/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/robots.txt: -------------------------------------------------------------------------------- 1 | # robotstxt.org 2 | 3 | User-agent: * 4 | -------------------------------------------------------------------------------- /db_templates/Python-UnitTest/Root/testSubmission/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "app/bower_components" 3 | } 4 | -------------------------------------------------------------------------------- /app/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeboardio/codeboard/HEAD/app/favicon.png -------------------------------------------------------------------------------- /db_templates/Python/Root/main.py: -------------------------------------------------------------------------------- 1 | # Main file of the Python program. 2 | 3 | print "Hello World!" 4 | -------------------------------------------------------------------------------- /app/images/close_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeboardio/codeboard/HEAD/app/images/close_dark.png -------------------------------------------------------------------------------- /app/images/close_light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeboardio/codeboard/HEAD/app/images/close_light.png -------------------------------------------------------------------------------- /app/images/logo/codeboard_logo_256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeboardio/codeboard/HEAD/app/images/logo/codeboard_logo_256.png -------------------------------------------------------------------------------- /app/images/logo/codeboard_logo_50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeboardio/codeboard/HEAD/app/images/logo/codeboard_logo_50.png -------------------------------------------------------------------------------- /app/images/users/defaults/smile1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeboardio/codeboard/HEAD/app/images/users/defaults/smile1.png -------------------------------------------------------------------------------- /app/images/users/defaults/smile2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeboardio/codeboard/HEAD/app/images/users/defaults/smile2.png -------------------------------------------------------------------------------- /app/images/users/defaults/smile3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeboardio/codeboard/HEAD/app/images/users/defaults/smile3.png -------------------------------------------------------------------------------- /app/images/users/defaults/smile4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeboardio/codeboard/HEAD/app/images/users/defaults/smile4.png -------------------------------------------------------------------------------- /app/images/users/defaults/smile5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeboardio/codeboard/HEAD/app/images/users/defaults/smile5.png -------------------------------------------------------------------------------- /app/components/angularTreeview/img/file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeboardio/codeboard/HEAD/app/components/angularTreeview/img/file.png -------------------------------------------------------------------------------- /app/components/angularTreeview/img/folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeboardio/codeboard/HEAD/app/components/angularTreeview/img/folder.png -------------------------------------------------------------------------------- /app/components/angularTreeview/img/preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeboardio/codeboard/HEAD/app/components/angularTreeview/img/preview.png -------------------------------------------------------------------------------- /db_templates/Python/Root/codeboard.json: -------------------------------------------------------------------------------- 1 | { 2 | "_comment": "Configuration for this Python project.", 3 | "MainFileForRunning": "main.py" 4 | } 5 | -------------------------------------------------------------------------------- /app/components/angularTreeview/img/jsfiddle01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeboardio/codeboard/HEAD/app/components/angularTreeview/img/jsfiddle01.png -------------------------------------------------------------------------------- /app/components/angularTreeview/img/jsfiddle02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeboardio/codeboard/HEAD/app/components/angularTreeview/img/jsfiddle02.png -------------------------------------------------------------------------------- /app/components/angularTreeview/img/folder-closed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeboardio/codeboard/HEAD/app/components/angularTreeview/img/folder-closed.png -------------------------------------------------------------------------------- /db_templates/Haskell/Root/Main.hs: -------------------------------------------------------------------------------- 1 | -- Main function of the Haskell program. 2 | 3 | module Main where 4 | 5 | main = do 6 | putStrLn "Hello Haskell World!" 7 | -------------------------------------------------------------------------------- /db_templates/C++/Root/main.cpp: -------------------------------------------------------------------------------- 1 | // Main function of the C++ program. 2 | 3 | #include 4 | 5 | int main() 6 | { 7 | std::cout << "Hello World!" << std::endl; 8 | } 9 | -------------------------------------------------------------------------------- /app/styles/style.css: -------------------------------------------------------------------------------- 1 | .nice-font { 2 | font-weight: 200; 3 | font-size: 22px; 4 | line-height: 1.8; 5 | } 6 | 7 | .dark-font-color { 8 | color: #666; 9 | } 10 | -------------------------------------------------------------------------------- /db_templates/C/Root/main.c: -------------------------------------------------------------------------------- 1 | /* Main function of the C program. */ 2 | 3 | #include 4 | #include 5 | 6 | int main() 7 | { 8 | puts("Hello World!"); 9 | return EXIT_SUCCESS; 10 | } 11 | -------------------------------------------------------------------------------- /db_templates/Haskell/Root/codeboard.json: -------------------------------------------------------------------------------- 1 | { 2 | "_comment": "Specify the main file used for compiling your application.", 3 | "MainFileForCompilation": "Main.hs", 4 | "GHCArgumentMainIs": "Main.main" 5 | } 6 | -------------------------------------------------------------------------------- /db_templates/Java/Root/Main.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Main class of the Java program. 3 | */ 4 | 5 | public class Main { 6 | 7 | public static void main(String[] args) { 8 | System.out.println("Hello World"); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /app/styles/userSettings.css: -------------------------------------------------------------------------------- 1 | 2 | .userSettingsBorder{ 3 | border: 1px solid #ddd; 4 | border-top: none; 5 | border-bottom-left-radius: 4px; 6 | border-bottom-right-radius: 4px; 7 | padding: 25px; 8 | margin-bottom: 5px; 9 | } 10 | -------------------------------------------------------------------------------- /lib/config/config.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _ = require('lodash'); 4 | 5 | /** 6 | * Load environment configuration 7 | */ 8 | module.exports = _.merge( 9 | require('./env/all.js'), 10 | require('./env/' + process.env.NODE_ENV + '.js') || {}); -------------------------------------------------------------------------------- /db_templates/Java/Root/codeboard.json: -------------------------------------------------------------------------------- 1 | { 2 | "_comment": "Specify the main file used for compiling your application. Specify the main class used for running your application.", 3 | "MainFileForCompilation": "Main.java", 4 | "MainClassForRunning": "Main" 5 | } 6 | -------------------------------------------------------------------------------- /lib/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "esnext": true, 4 | "bitwise": true, 5 | "eqeqeq": true, 6 | "immed": true, 7 | "latedef": true, 8 | "newcap": true, 9 | "noarg": true, 10 | "regexp": true, 11 | "undef": true, 12 | "smarttabs": true 13 | } -------------------------------------------------------------------------------- /test/server/src_examples/python/py_error_missing_setting.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "Python", 3 | "files": [ 4 | { 5 | "filename": "Root/application.py", 6 | "content": "print \"Goodbye, World!\" " 7 | } 8 | ], 9 | "action": "compile", 10 | "stream": false 11 | } -------------------------------------------------------------------------------- /test/server/src_examples/c/c_wrong_id1.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "C", 3 | "files": [ 4 | { 5 | "filename": "Root/b.c", 6 | "content": "#include \"b.h\"\n#include \"c.h\"\n int foo () {bar(); return 1;}" 7 | } 8 | ], 9 | "action": "compile", 10 | "stream": false 11 | } -------------------------------------------------------------------------------- /test/server/src_examples/cpp/cpp_wrong_id1.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "C++", 3 | "files": [ 4 | { 5 | "filename": "Root/b.h", 6 | "content": "#ifndef B_MODULE\n #define B_MODULE\n int foo();\n #endif" 7 | } 8 | ], 9 | "action": "compile", 10 | "stream": false 11 | } -------------------------------------------------------------------------------- /test/server/src_examples/c/c_incremental1.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "C", 3 | "files": [ 4 | { 5 | "filename": "Root/b.c", 6 | "content": "#include \"b.h\"\n#include \"c.h\"\n int foo () {bar(); return 1;}" 7 | } 8 | ], 9 | "action": "compile", 10 | "stream": false 11 | } -------------------------------------------------------------------------------- /test/server/src_examples/c/c_error_incremental1.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "C", 3 | "files": [ 4 | { 5 | "filename": "Root/b.c", 6 | "content": "#include \"b.h\"\n#include \"c.h\"\n int foo () {bar(); return 1;}" 7 | } 8 | ], 9 | "action": "compile", 10 | "stream": false 11 | } -------------------------------------------------------------------------------- /test/server/src_examples/cpp/cpp_incremental1.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "C++", 3 | "files": [ 4 | { 5 | "filename": "Root/b.cpp", 6 | "content": "#include \"b.h\"\n#include \"c.h\"\n int foo () {bar(); return 1;}" 7 | } 8 | ], 9 | "action": "compile", 10 | "stream": false 11 | } -------------------------------------------------------------------------------- /test/server/src_examples/haskell/hs_error_missing_setting.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "Haskell", 3 | "files": [ 4 | { 5 | "filename": "Root/application.hs", 6 | "content": "main = do putStrLn \"Hello Haskell World!\"" 7 | } 8 | ], 9 | "action": "compile", 10 | "stream": false 11 | } -------------------------------------------------------------------------------- /test/server/src_examples/cpp/cpp_error_incremental1.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "C++", 3 | "files": [ 4 | { 5 | "filename": "Root/b.cpp", 6 | "content": "#include \"b.h\"\n#include \"c.h\"\n int foo () {bar(); return 1;}" 7 | } 8 | ], 9 | "action": "compile", 10 | "stream": false 11 | } -------------------------------------------------------------------------------- /db_templates/Python-UnitTest/Root/codeboard.json: -------------------------------------------------------------------------------- 1 | { 2 | "_comment": "Configuration for this Python-UnitTest project.", 3 | "MainFileForRunning": "./Root/src/main.py", 4 | "DirectoryForSourceFiles": "./Root/src", 5 | "DirectoryForTestFiles": "./Root/test", 6 | "DirectoryForTestSubmissionFiles": "./Root/testSubmission" 7 | } 8 | -------------------------------------------------------------------------------- /test/server/src_examples/c/c_error_one_file.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "C", 3 | "files": [ 4 | { 5 | "filename": "Root/application.c", 6 | "content": "#include \n int main() { printf(\"Hello, C World! \"); foo(); \n\treturn 0; }" 7 | } 8 | ], 9 | "action": "compile", 10 | "stream": false 11 | } -------------------------------------------------------------------------------- /app/scripts/resources/sessionRes.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by hce on 7/25/14. 3 | * 4 | * A service for the resource that belongs the a user session. 5 | */ 6 | 7 | 'use strict'; 8 | 9 | angular.module('codeboardApp') 10 | 11 | .factory('SessionRes', ['$resource', function($resource) { 12 | return $resource('/api/session'); 13 | }]) 14 | -------------------------------------------------------------------------------- /test/server/src_examples/cpp/cpp_error_one_file.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "C++", 3 | "files": [ 4 | { 5 | "filename": "Root/application.cpp", 6 | "content": "#include \n int main() { std::cout << \"Hello C++ world!\" << std::endl; foo(); \n\treturn 0; }" 7 | } 8 | ], 9 | "action": "compile", 10 | "stream": false 11 | } -------------------------------------------------------------------------------- /test/server/src_examples/java/j_error_missing_setting.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "Java", 3 | "files": [ 4 | { 5 | "filename": "Root/Application.java", 6 | "content": "public class Application { public static void main(String[] args) {System.out.println(\"Hello Java Test-1 \"); }}" 7 | } 8 | ], 9 | "action": "compile", 10 | "stream": false 11 | } -------------------------------------------------------------------------------- /db_templates/Haskell-HSpec/Root/codeboard.json: -------------------------------------------------------------------------------- 1 | { 2 | "_comment": "Configuration for this Haskell-HSpec project.", 3 | "MainFileForCompilation": "./Root/Src/Main.hs", 4 | "GHCArgumentMainIs": "Root.Src.Main.main", 5 | "DirectoryForSourceFiles": "./Root/Src", 6 | "DirectoryForTestFiles": "./Root/Test", 7 | "DirectoryForTestSubmissionFiles": "./Root/TestSubmission" 8 | } 9 | -------------------------------------------------------------------------------- /app/styles/projectSummary.css: -------------------------------------------------------------------------------- 1 | .projectSummary-listing { 2 | list-style: none; 3 | padding-top: 20px; 4 | } 5 | 6 | .projectSummary-listing-metadata { 7 | float: right; 8 | margin-top: 20px; 9 | color: #5e5e5e; 10 | font-size: 12px; 11 | } 12 | 13 | .projectSummary-listing-description { 14 | white-space: pre-line; 15 | max-width: 650px; 16 | padding-top: 20px; 17 | } 18 | -------------------------------------------------------------------------------- /test/server/src_examples/c/c_run_file.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "C", 3 | "files": [ 4 | { 5 | "filename": "Root/application.c", 6 | "content": "/*Keep the main routine in the file application.c;\n otherwise Codeboard does not work*/\n\n#include \nint main() { \n\tprintf(\"Hello, C World! \"); \n\treturn 0; \n}" 7 | } 8 | ], 9 | "action": "compile", 10 | "stream": false 11 | } -------------------------------------------------------------------------------- /db_templates/Java-JUnit/Root/codeboard.json: -------------------------------------------------------------------------------- 1 | { 2 | "_comment": "Configuration for this Java-JUnit project.", 3 | "MainClassForRunning": "Main", 4 | "ClassPath": "/usr/share/java/*", 5 | "DirectoryForClassFiles": "./Root/bin", 6 | "DirectoryForSourceFiles": "./Root/src", 7 | "DirectoryForTestFiles": "./Root/test", 8 | "DirectoryForTestSubmissionFiles": "./Root/test_submission" 9 | } 10 | -------------------------------------------------------------------------------- /test/server/src_examples/python/py_one_file.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "Python", 3 | "files": [ 4 | { 5 | "filename": "Root/application.py", 6 | "content": "print \"Goodbye, World!\" " 7 | }, 8 | { 9 | "filename": "Root/codeboard.json", 10 | "content": "{\n\t\"MainFileForRunning\":\"application.py\"\n}" 11 | } 12 | ], 13 | "action": "compile", 14 | "stream": false 15 | } -------------------------------------------------------------------------------- /test/server/src_examples/c/c_one_file.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "C", 3 | "files": [ 4 | { 5 | "filename": "Root/application.c", 6 | "content": "/*Keep the main routine in the file application.c;\n otherwise Codeboard does not work*/\n\n#include \nint main() { \n\tprintf(\"Hello, C World! \"); \n\treturn 0; \n}" 7 | } 8 | ], 9 | "action": "compile", 10 | "stream": false 11 | } 12 | -------------------------------------------------------------------------------- /test/server/src_examples/python/py_incremental1.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "Python", 3 | "files": [ 4 | { 5 | "filename": "Root/b.py", 6 | "content": "def foo():\n\tprint \"Goodbye, foo!\"" 7 | }, 8 | { 9 | "filename": "Root/codeboard.json", 10 | "content": "{\n\t\"MainFileForRunning\":\"application.py\"\n}" 11 | } 12 | ], 13 | "action": "compile", 14 | "stream": false 15 | } -------------------------------------------------------------------------------- /test/server/src_examples/python/py_wrong_id1.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "Python", 3 | "files": [ 4 | { 5 | "filename": "Root/b.py", 6 | "content": "def foo():\n\tprint \"Goodbye, foo!\"" 7 | }, 8 | { 9 | "filename": "Root/codeboard.json", 10 | "content": "{\n\t\"MainFileForRunning\":\"application.py\"\n}" 11 | } 12 | ], 13 | "action": "compile", 14 | "stream": false 15 | } -------------------------------------------------------------------------------- /test/server/src_examples/python/py_error_one_file.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "Python", 3 | "files": [ 4 | { 5 | "filename": "Root/application.py", 6 | "content": "foo23()\nprint \"Goodbye, World!\"" 7 | }, 8 | { 9 | "filename": "Root/codeboard.json", 10 | "content": "{\n\t\"MainFileForRunning\":\"application.py\"\n}" 11 | } 12 | ], 13 | "action": "compile", 14 | "stream": false 15 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # NodeJS dependencies 2 | node_modules 3 | 4 | # Bower dependencies 5 | app/bower_components 6 | 7 | # tmp folders created by Grunt 8 | .tmp 9 | .sass-cache 10 | 11 | # the folder created when running "grunt build" 12 | dist 13 | 14 | # Ignore the profile pictures of users 15 | app/images/users/profiles 16 | 17 | # Ignore everything in folder test/coverage which has generated coverage reports 18 | test/coverage 19 | -------------------------------------------------------------------------------- /test/server/src_examples/cpp/cpp_one_file.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "C++", 3 | "files": [ 4 | { 5 | "filename": "Root/application.cpp", 6 | "content": "/*Keep the main routine in the file application.c;\n otherwise Codeboard does not work*/\n\n#include \nint main() { \n\tstd::cout << \"Hello C++ world!\" << std::endl; \n\treturn 0; \n}" 7 | } 8 | ], 9 | "action": "compile", 10 | "stream": false 11 | } -------------------------------------------------------------------------------- /test/server/src_examples/cpp/cpp_run_file.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "C++", 3 | "files": [ 4 | { 5 | "filename": "Root/application.cpp", 6 | "content": "/*Keep the main routine in the file application.c;\n otherwise Codeboard does not work*/\n\n#include \nint main() { \n\tstd::cout << \"Hello C++ world!\" << std::endl; \n\treturn 0; \n}" 7 | } 8 | ], 9 | "action": "compile", 10 | "stream": false 11 | } -------------------------------------------------------------------------------- /test/server/src_examples/python/py_error_setting.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "Python", 3 | "files": [ 4 | { 5 | "filename": "Root/application.py", 6 | "content": "foo23()\nprint \"Goodbye, World!\"" 7 | }, 8 | { 9 | "filename": "Root/codeboard.json", 10 | "content": "{\n\t\"MainFileForCompilation\":\"application.hs\"\n ERROR" 11 | } 12 | ], 13 | "action": "compile", 14 | "stream": false 15 | } -------------------------------------------------------------------------------- /test/server/src_examples/python/py_run_invalid_id.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "Python", 3 | "files": [ 4 | { 5 | "filename": "Root/application.py", 6 | "content": "print \"Goodbye, World!\" " 7 | }, 8 | { 9 | "filename": "Root/codeboard.json", 10 | "content": "{\n\t\"MainFileForRunning\":\"application.py\"\n}" 11 | } 12 | ], 13 | "action": "run", 14 | "id": "INVALID_ID", 15 | "stream": false 16 | } -------------------------------------------------------------------------------- /db_templates/Haskell-HSpec/Root/Src/Finder.hs: -------------------------------------------------------------------------------- 1 | -- File containing utility functions for lists. 2 | 3 | module Root.Src.Finder where 4 | 5 | -- Returns the maximum element in a list. 6 | maxFunction :: [Int] -> Int 7 | maxFunction [] = error "List is empty. Please provide a non-empty list." 8 | maxFunction [x] = x 9 | maxFunction (x:xs) 10 | | x > maxTail = x 11 | | otherwise = maxTail 12 | where maxTail = maxFunction xs 13 | -------------------------------------------------------------------------------- /test/server/src_examples/python/py_error_incremental1.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "Python", 3 | "files": [ 4 | { 5 | "filename": "Root/application.py", 6 | "content": "from b import foo\nfoo()\nprint \"Goodbye, World!\"" 7 | }, 8 | { 9 | "filename": "Root/codeboard.json", 10 | "content": "{\n\t\"MainFileForRunning\":\"application.py\"\n}" 11 | } 12 | ], 13 | "action": "compile", 14 | "stream": false 15 | } -------------------------------------------------------------------------------- /app/scripts/resources/userprojectRes.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('codeboardApp') 4 | 5 | .factory('UserProjectRes', ['$resource', function($resource) { 6 | return $resource( 7 | '/api/projects/:projectId/userprojects/:userprojectId', 8 | {userprojectId: '@userprojectId', projectId: '@projectId'} // when doing non-post request, the :projectId is filled in through the id property of the project-object 9 | ); 10 | }]); 11 | -------------------------------------------------------------------------------- /db_templates/Python-UnitTest/Root/src/main.py: -------------------------------------------------------------------------------- 1 | ## 2 | # Main function of the Python program. 3 | # 4 | ## 5 | 6 | from finder import maximum_in_list 7 | 8 | def main(): 9 | # we print a heading and make it bigger using HTML formatting 10 | print "

-- Maximun Element Finder --

" 11 | maximum = maximum_in_list([2, 3, 42, 12, 7]) 12 | print "The maximum element is: ", maximum 13 | 14 | 15 | if __name__ == '__main__': 16 | main() 17 | -------------------------------------------------------------------------------- /test/server/src_examples/c/c_error_incremental2.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "C", 3 | "files": [ 4 | { 5 | "filename": "Root/b.c", 6 | "content": "#include \"b.h\"\n#include \"c.h\"\n int foo () {bar(); return 1;}" 7 | }, 8 | { 9 | "filename": "Root/c.c", 10 | "content": "#include \n#include \"c.h\"\n int bar () {printf(\"Hello C\");return 2;}" 11 | } 12 | ], 13 | "action": "compile", 14 | "stream": false 15 | } -------------------------------------------------------------------------------- /test/server/src_examples/haskell/hs_incremental1.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "Haskell", 3 | "files": [ 4 | { 5 | "filename": "Root/B.hs", 6 | "content": "module B (foo) where foo = do putStrLn \"Hello B\"" 7 | }, 8 | { 9 | "filename": "Root/codeboard.json", 10 | "content": "{\n\t\"MainFileForCompilation\":\"application.hs\",\n\t\"GHCArgumentMainIs\":\"main\"\n}" 11 | } 12 | ], 13 | "action": "compile", 14 | "stream": false 15 | } -------------------------------------------------------------------------------- /test/server/src_examples/haskell/hs_one_file.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "Haskell", 3 | "files": [ 4 | { 5 | "filename": "Root/application.hs", 6 | "content": "main = do putStrLn \"Hello Haskell World!\"" 7 | }, 8 | { 9 | "filename": "Root/codeboard.json", 10 | "content": "{\n\t\"MainFileForCompilation\":\"application.hs\",\n\t\"GHCArgumentMainIs\":\"main\"\n}" 11 | } 12 | ], 13 | "action": "compile", 14 | "stream": false 15 | } -------------------------------------------------------------------------------- /test/server/src_examples/haskell/hs_run_file.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "Haskell", 3 | "files": [ 4 | { 5 | "filename": "Root/application.hs", 6 | "content": "main = do putStrLn \"Hello Haskell World!\"" 7 | }, 8 | { 9 | "filename": "Root/codeboard.json", 10 | "content": "{\n\t\"MainFileForCompilation\":\"application.hs\",\n\t\"GHCArgumentMainIs\":\"main\"\n}" 11 | } 12 | ], 13 | "action": "compile", 14 | "stream": false 15 | } -------------------------------------------------------------------------------- /test/server/src_examples/haskell/hs_wrong_id1.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "Haskell", 3 | "files": [ 4 | { 5 | "filename": "Root/B.hs", 6 | "content": "module B (foo) where foo = do putStrLn \"Hello B\"" 7 | }, 8 | { 9 | "filename": "Root/codeboard.json", 10 | "content": "{\n\t\"MainFileForCompilation\":\"application.hs\",\n\t\"GHCArgumentMainIs\":\"B.main\"\n}" 11 | } 12 | ], 13 | "action": "compile", 14 | "stream": false 15 | } -------------------------------------------------------------------------------- /app/scripts/directives/ngEnter.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('codeboardApp') 4 | .directive('ngEnter', function () { 5 | return function(scope, element, attrs) { 6 | element.bind("keydown keypress", function(event) { 7 | if(event.which === 13) { 8 | scope.$apply(function () { 9 | scope.$eval(attrs.ngEnter) 10 | }); 11 | 12 | event.preventDefault(); 13 | } 14 | }); 15 | } 16 | }); 17 | -------------------------------------------------------------------------------- /test/server/src_examples/haskell/hs_error_one_file.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "Haskell", 3 | "files": [ 4 | { 5 | "filename": "Root/application.hs", 6 | "content": "main = do\n foo\n putStrLn \"Hello Haskell World!\"" 7 | }, 8 | { 9 | "filename": "Root/codeboard.json", 10 | "content": "{\n\t\"MainFileForCompilation\":\"application.hs\",\n\t\"GHCArgumentMainIs\":\"main\"\n}" 11 | } 12 | ], 13 | "action": "compile", 14 | "stream": false 15 | } -------------------------------------------------------------------------------- /test/server/src_examples/haskell/hs_error_setting_file.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "Haskell", 3 | "files": [ 4 | { 5 | "filename": "Root/application.hs", 6 | "content": "main = do putStrLn \"Hello Haskell World!\"" 7 | }, 8 | { 9 | "filename": "Root/codeboard.json", 10 | "content": "{\n\t\"MainFileForCompilation\":\"application.hs\",\n\t\"GHCArgumentMainIs\":\"main\"\n ERROR" 11 | } 12 | ], 13 | "action": "compile", 14 | "stream": false 15 | } -------------------------------------------------------------------------------- /app/styles/projectListing.css: -------------------------------------------------------------------------------- 1 | .project-listing { 2 | list-style: none; 3 | border-bottom: 1px solid #eee; 4 | padding-top: 20px; 5 | padding-bottom: 20px; 6 | } 7 | 8 | .project-listing-planguage { 9 | float: right; 10 | margin-top: 20px; 11 | font-weight: bold; 12 | color: #5e5e5e; 13 | } 14 | 15 | .project-listing-metadata { 16 | color: #5e5e5e; 17 | font-size: 12px; 18 | } 19 | 20 | .project-listing-description { 21 | max-width: 650px; 22 | } 23 | -------------------------------------------------------------------------------- /test/server/src_examples/cpp/cpp_error_incremental2.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "C++", 3 | "files": [ 4 | { 5 | "filename": "Root/b.cpp", 6 | "content": "#include \"b.h\"\n#include \"c.h\"\n int foo () {bar(); return 1;}" 7 | }, 8 | { 9 | "filename": "Root/c.cpp", 10 | "content": "#include \n#include \"c.h\"\n int bar () {std::cout << \"Hello C++ world!\" << std::endl;return 2;}" 11 | } 12 | ], 13 | "action": "compile", 14 | "stream": false 15 | } -------------------------------------------------------------------------------- /test/server/src_examples/haskell/hs_run_invalid_id.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "Haskell", 3 | "files": [ 4 | { 5 | "filename": "Root/application.hs", 6 | "content": "main = do putStrLn \"Hello Haskell World!\"" 7 | }, 8 | { 9 | "filename": "Root/codeboard.json", 10 | "content": "{\n\t\"MainFileForCompilation\":\"application.hs\",\n\t\"GHCArgumentMainIs\":\"main\"\n}" 11 | } 12 | ], 13 | "action": "run", 14 | "id": "INVALID_ID", 15 | "stream": false 16 | } -------------------------------------------------------------------------------- /test/server/src_examples/java/j_incremental1.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "Java", 3 | "files": [ 4 | { 5 | "filename": "Root/B.java", 6 | "content": "public class B { public B() {C c = new C(); System.out.println(\"Hello B\"); }}" 7 | }, 8 | { 9 | "filename": "Root/codeboard.json", 10 | "content": "{\n\t\"MainFileForCompilation\": \"Application.java\",\n\t\"MainClassForRunning\":\"Application\"\n}" 11 | } 12 | ], 13 | "action": "compile", 14 | "stream": false 15 | } -------------------------------------------------------------------------------- /test/server/src_examples/java/j_wrong_id1.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "Java", 3 | "files": [ 4 | { 5 | "filename": "Root/B.java", 6 | "content": "public class B { public B() {C c = new C(); System.out.println(\"Hello B\"); }}" 7 | }, 8 | { 9 | "filename": "Root/codeboard.json", 10 | "content": "{\n\t\"MainFileForCompilation\": \"Application.java\",\n\t\"MainClassForRunning\":\"Application\"\n}" 11 | } 12 | ], 13 | "action": "compile", 14 | "stream": false 15 | } -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "browser": true, 4 | "esnext": true, 5 | "bitwise": true, 6 | "camelcase": true, 7 | "curly": true, 8 | "eqeqeq": true, 9 | "immed": true, 10 | "indent": 2, 11 | "latedef": true, 12 | "newcap": true, 13 | "noarg": true, 14 | "quotmark": "single", 15 | "regexp": true, 16 | "undef": true, 17 | "unused": true, 18 | "strict": true, 19 | "trailing": true, 20 | "smarttabs": true, 21 | "globals": { 22 | "angular": false 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/scripts/controllers/usersAllCtrl.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('codeboardApp') 4 | .controller('usersAllCtrl', ['$scope', '$http', function($scope, $http) { 5 | 6 | // the users to display 7 | $scope.users = []; 8 | 9 | var init = function() { 10 | $http 11 | .get('/api/users') 12 | .success(function(data) { 13 | $scope.users = data; 14 | 15 | }) 16 | .error(function(err) { 17 | 18 | }); 19 | }(); 20 | 21 | }]); 22 | -------------------------------------------------------------------------------- /test/server/src_examples/java/j_error_setting_file.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "Java", 3 | "files": [ 4 | { 5 | "filename": "Root/Application.java", 6 | "content": "public class Application { public static void main(String[] args) {System.out.println(\"Hello \"); b.foo(); }}" 7 | }, 8 | { 9 | "filename": "Root/codeboard.json", 10 | "content": "{\n\t\"MainFileForCompilation\":\"application.hs\"\n ERROR" 11 | } 12 | ], 13 | "action": "compile", 14 | "stream": false 15 | } -------------------------------------------------------------------------------- /test/server/src_examples/python/py_error_main.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "Python", 3 | "files": [ 4 | { 5 | "filename": "Root/b.py", 6 | "content": "def foo():\n\tprint \"Goodbye, foo!\"" 7 | }, 8 | { 9 | "filename": "Root/c.py", 10 | "content": "def bar():\n\tprint \"Goodbye, bar!\"" 11 | }, 12 | { 13 | "filename": "Root/codeboard.json", 14 | "content": "{\n\t\"MainFileForRunning\":\"application.py\"\n}" 15 | } 16 | ], 17 | "action": "compile", 18 | "stream": false 19 | } -------------------------------------------------------------------------------- /test/server/src_examples/java/j_error.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "Java", 3 | "files": [ 4 | { 5 | "filename": "Root/Application.java", 6 | "content": "public class Application { public static void main(String[] args) {System.out.println(\"Hello \"); b.foo(); }}" 7 | }, 8 | { 9 | "filename": "Root/codeboard.json", 10 | "content": "{\n\t\"MainFileForCompilation\": \"Application.java\",\n\t\"MainClassForRunning\":\"Application\"\n}" 11 | } 12 | ], 13 | "action": "compile", 14 | "stream": false 15 | } -------------------------------------------------------------------------------- /test/server/src_examples/java/j_one_file.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "Java", 3 | "files": [ 4 | { 5 | "filename": "Root/Application.java", 6 | "content": "public class Application { public static void main(String[] args) {System.out.println(\"Hello Java Test-1 \"); }}" 7 | }, 8 | { 9 | "filename": "Root/codeboard.json", 10 | "content": "{\n\t\"MainFileForCompilation\": \"Application.java\",\n\t\"MainClassForRunning\":\"Application\"\n}" 11 | } 12 | ], 13 | "action": "compile", 14 | "stream": false 15 | } -------------------------------------------------------------------------------- /test/server/src_examples/java/j_run_file.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "Java", 3 | "files": [ 4 | { 5 | "filename": "Root/Application.java", 6 | "content": "public class Application { public static void main(String[] args) {System.out.println(\"Hello Java Test-1 \"); }}" 7 | }, 8 | { 9 | "filename": "Root/codeboard.json", 10 | "content": "{\n\t\"MainFileForCompilation\": \"Application.java\",\n\t\"MainClassForRunning\":\"Application\"\n}" 11 | } 12 | ], 13 | "action": "compile", 14 | "stream": false 15 | } -------------------------------------------------------------------------------- /lib/config/env/test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | 5 | env: 'test', 6 | 7 | envFolder: 'app', 8 | 9 | db: { 10 | database: 'codeboard-test' 11 | }, 12 | 13 | mongo: { 14 | uri: 'mongodb://localhost/codeboardLogs-test' 15 | }, 16 | 17 | mantra : { 18 | ip: '127.0.0.1', 19 | url: 'http://127.0.0.1', 20 | port: 9090 21 | }, 22 | 23 | kali: { 24 | url: 'http://127.0.0.1', 25 | port: 9091 26 | }, 27 | 28 | tara: { 29 | url: 'http://127.0.0.1', 30 | port: 9090 31 | } 32 | 33 | }; 34 | -------------------------------------------------------------------------------- /lib/config/env/development.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | 5 | env: 'development', 6 | 7 | envFolder: 'app', 8 | 9 | db: { 10 | database: 'codeboard' 11 | }, 12 | 13 | mongo: { 14 | uri: 'mongodb://localhost/fullstack-dev' 15 | }, 16 | 17 | mantra : { 18 | ip: '127.0.0.1', 19 | url: 'http://127.0.0.1', 20 | port: 9090 21 | }, 22 | 23 | kali: { 24 | url: 'http://127.0.0.1', 25 | port: 9091 26 | }, 27 | 28 | tara: { 29 | url: 'http://127.0.0.1', 30 | port: 9090 31 | } 32 | 33 | }; 34 | -------------------------------------------------------------------------------- /test/server/src_examples/python/py_error_incremental2.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "Python", 3 | "files": [ 4 | { 5 | "filename": "Root/application.py", 6 | "content": "from b import foo\nfoo()\nprint \"Goodbye, World!\"" 7 | }, 8 | { 9 | "filename": "Root/c.py", 10 | "content": "def bar():\n\tprint \"Goodbye, bar!\"" 11 | }, 12 | { 13 | "filename": "Root/codeboard.json", 14 | "content": "{\n\t\"MainFileForRunning\":\"application.py\"\n}" 15 | } 16 | ], 17 | "action": "compile", 18 | "stream": false 19 | } -------------------------------------------------------------------------------- /test/server/src_examples/python/py_error_several_files.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "Python", 3 | "files": [ 4 | { 5 | "filename": "Root/application.py", 6 | "content": "from b import foo\nfoo()\nprint \"Goodbye, World!\"" 7 | }, 8 | { 9 | "filename": "Root/c.py", 10 | "content": "def bar():\n\tprint \"Goodbye, bar!\"" 11 | }, 12 | { 13 | "filename": "Root/codeboard.json", 14 | "content": "{\n\t\"MainFileForRunning\":\"application.py\"\n}" 15 | } 16 | ], 17 | "action": "compile", 18 | "stream": false 19 | } -------------------------------------------------------------------------------- /test/server/src_examples/java/j_run_invalid_id.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "Java", 3 | "files": [ 4 | { 5 | "filename": "Root/Application.java", 6 | "content": "public class Application { public static void main(String[] args) {System.out.println(\"Hello Java Test-1 \"); }}" 7 | }, 8 | { 9 | "filename": "Root/codeboard.json", 10 | "content": "{\n\t\"MainFileForCompilation\": \"Application.java\",\n\t\"MainClassForRunning\":\"Application\"\n}" 11 | } 12 | ], 13 | "action": "run", 14 | "id": "INVALID_ID", 15 | "stream": false 16 | } -------------------------------------------------------------------------------- /test/server/src_examples/haskell/hs_error_main.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "Haskell", 3 | "files": [ 4 | { 5 | "filename": "Root/B.hs", 6 | "content": "module B (foo) where foo = do putStrLn \"Hello B\"" 7 | }, 8 | { 9 | "filename": "Root/C.hs", 10 | "content": "module C (bar) where bar = do putStrLn \"Hello C\"" 11 | }, 12 | { 13 | "filename": "Root/codeboard.json", 14 | "content": "{\n\t\"MainFileForCompilation\":\"application.hs\",\n\t\"GHCArgumentMainIs\":\"main\"\n}" 15 | } 16 | ], 17 | "action": "compile", 18 | "stream": false 19 | } -------------------------------------------------------------------------------- /db_templates/Haskell-HSpec/Root/Src/Main.hs: -------------------------------------------------------------------------------- 1 | -- File containing the main function of this program. 2 | 3 | module Root.Src.Main where 4 | 5 | -- Import the module that defines the function maxElement 6 | import Root.Src.Finder 7 | 8 | 9 | -- The main entry point. 10 | main = do 11 | -- We print a heading and make it bigger using HTML formatting. 12 | putStrLn "

-- Maximun Element Finder --

" 13 | 14 | -- Call the function to find the maximum element in a list. 15 | let x = maxFunction [2, 3, 42, 12, 7] 16 | putStrLn ("The maximum element is: " ++ (show x)) 17 | -------------------------------------------------------------------------------- /test/server/src_examples/java/j_no_main_specified.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "Java", 3 | "files": [ 4 | { 5 | "filename": "Root/B.java", 6 | "content": "public class B { public B() {C c = new C(); System.out.println(\"Hello B\"); }}" 7 | }, 8 | { 9 | "filename": "Root/C.java", 10 | "content": "public class C { public C() {System.out.println(\"Hello C\"); }}" 11 | }, 12 | { 13 | "filename": "Root/codeboard.json", 14 | "content": "{\n\t\"MainClassForRunning\":\"Application\"\n}" 15 | } 16 | ], 17 | "action": "compile", 18 | "stream": false 19 | } -------------------------------------------------------------------------------- /lib/models/templateProject.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by haches on 7/25/14. 3 | * 4 | * The ORM model for templates of projects. 5 | */ 6 | 7 | 8 | module.exports = function(sequelize, DataTypes) { 9 | 10 | var templateProject = sequelize.define( 11 | 'TemplateProject', 12 | { 13 | // the programming language 14 | language: DataTypes.STRING 15 | }, 16 | { 17 | classMethods: { 18 | associate: function(models) { 19 | templateProject.hasMany(models.TemplateFile, {as: 'fileSet'}); 20 | } 21 | } 22 | } 23 | ); 24 | 25 | return templateProject; 26 | }; -------------------------------------------------------------------------------- /test/server/src_examples/haskell/hs_error_incremental1.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "Haskell", 3 | "files": [ 4 | { 5 | "filename": "Root/application.hs", 6 | "content": "import B(foo)\nimport C(bar)\n\nmain = do\n putStrLn \"Hello Haskell World!\"\n foo\n bar\n\n" 7 | }, 8 | { 9 | "filename": "Root/C.hs", 10 | "content": "module C (bar) where bar = do putStrLn \"Hello C\"" 11 | }, 12 | { 13 | "filename": "Root/codeboard.json", 14 | "content": "{\n\t\"MainFileForCompilation\":\"application.hs\",\n\t\"GHCArgumentMainIs\":\"main\"\n}" 15 | } 16 | ], 17 | "action": "compile", 18 | "stream": false 19 | } -------------------------------------------------------------------------------- /test/server/src_examples/haskell/hs_error_several_files.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "Haskell", 3 | "files": [ 4 | { 5 | "filename": "Root/application.hs", 6 | "content": "import B(foo)\nimport C(bar)\n\nmain = do\n putStrLn \"Hello Haskell World!\"\n foo\n bar\n\n" 7 | }, 8 | { 9 | "filename": "Root/C.hs", 10 | "content": "module C (bar) where bar = do putStrLn \"Hello C\"" 11 | }, 12 | { 13 | "filename": "Root/codeboard.json", 14 | "content": "{\n\t\"MainFileForCompilation\":\"application.hs\",\n\t\"GHCArgumentMainIs\":\"main\"\n}" 15 | } 16 | ], 17 | "action": "compile", 18 | "stream": false 19 | } -------------------------------------------------------------------------------- /test/server/src_examples/python/py_incremental2.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "Python", 3 | "files": [ 4 | { 5 | "filename": "Root/application.py", 6 | "content": "from b import foo\nfoo()\nprint \"Goodbye, World!\"" 7 | }, 8 | { 9 | "filename": "Root/b.py", 10 | "content": "def foo():\n\tprint \"Goodbye, foo!\"" 11 | }, 12 | { 13 | "filename": "Root/c.py", 14 | "content": "def bar():\n\tprint \"Goodbye, bar!\"" 15 | }, 16 | { 17 | "filename": "Root/codeboard.json", 18 | "content": "{\n\t\"MainFileForRunning\":\"application.py\"\n}" 19 | } 20 | ], 21 | "action": "compile", 22 | "stream": false 23 | } -------------------------------------------------------------------------------- /test/server/src_examples/python/py_wrong_id2.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "Python", 3 | "files": [ 4 | { 5 | "filename": "Root/application.py", 6 | "content": "from b import foo\nfoo()\nprint \"Goodbye, World!\"" 7 | }, 8 | { 9 | "filename": "Root/b.py", 10 | "content": "def foo():\n\tprint \"Goodbye, foo!\"" 11 | }, 12 | { 13 | "filename": "Root/c.py", 14 | "content": "def bar():\n\tprint \"Goodbye, bar!\"" 15 | }, 16 | { 17 | "filename": "Root/codeboard.json", 18 | "content": "{\n\t\"MainFileForRunning\":\"application.py\"\n}" 19 | } 20 | ], 21 | "action": "compile", 22 | "stream": false 23 | } -------------------------------------------------------------------------------- /test/server/src_examples/python/py_several_files.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "Python", 3 | "files": [ 4 | { 5 | "filename": "Root/application.py", 6 | "content": "from b import foo\nfoo()\nprint \"Goodbye, World!\"" 7 | }, 8 | { 9 | "filename": "Root/b.py", 10 | "content": "def foo():\n\tprint \"Goodbye, foo!\"" 11 | }, 12 | { 13 | "filename": "Root/c.py", 14 | "content": "def bar():\n\tprint \"Goodbye, bar!\"" 15 | }, 16 | { 17 | "filename": "Root/codeboard.json", 18 | "content": "{\n\t\"MainFileForRunning\":\"application.py\"\n}" 19 | } 20 | ], 21 | "action": "compile", 22 | "stream": false 23 | } -------------------------------------------------------------------------------- /lib/controllers/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'); 4 | 5 | /** 6 | * Send partial, or 404 if it doesn't exist 7 | */ 8 | exports.partials = function(req, res) { 9 | var stripped = req.url.split('.')[0]; 10 | var requestedView = path.join('./', stripped); 11 | res.render(requestedView, function(err, html) { 12 | if(err) { 13 | console.log("Error rendering partial '" + requestedView + "'\n", err); 14 | res.status(404); 15 | res.send(404); 16 | } else { 17 | res.send(html); 18 | } 19 | }); 20 | }; 21 | 22 | /** 23 | * Send our single page app 24 | */ 25 | exports.index = function(req, res) { 26 | res.render('index'); 27 | }; 28 | -------------------------------------------------------------------------------- /db_templates/Python-UnitTest/Root/src/finder.py: -------------------------------------------------------------------------------- 1 | ## 2 | # A collection of functions to search in lists. 3 | # 4 | ## 5 | 6 | 7 | # Returns the minimum element in a list of integers 8 | def maximum_in_list(list): 9 | 10 | # Your task: 11 | # - Check if this function works for all possible integers. 12 | # - Throw a ValueError if the input list is empty (see code below) 13 | 14 | # if not list: 15 | # raise ValueError('List may not be empty') 16 | 17 | max_element = 0 18 | 19 | # we loop trough the list and look at each element 20 | for element in list: 21 | if element > max_element: 22 | max_element = element 23 | 24 | return max_element 25 | -------------------------------------------------------------------------------- /lib/config/env/production.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | 5 | env: 'production', 6 | 7 | envFolder: 'public', 8 | 9 | db: { 10 | database: 'codeboard' 11 | }, 12 | 13 | mongo: { 14 | uri: 'mongodb://localhost/codeboardLogs' 15 | }, 16 | 17 | codeboard: { 18 | // because we use https in production, we also need to use wss 19 | wsHostname: 'wss://codeboard.io' 20 | }, 21 | 22 | mantra : { 23 | ip: '127.0.0.1', 24 | url: 'http://127.0.0.1', 25 | port: 9090 26 | }, 27 | 28 | kali: { 29 | url: 'http://127.0.0.1', 30 | port: 9091 31 | }, 32 | 33 | tara: { 34 | url: 'http://127.0.0.1', 35 | port: 9090 36 | } 37 | 38 | }; 39 | -------------------------------------------------------------------------------- /app/styles/docs.css: -------------------------------------------------------------------------------- 1 | .docContent { 2 | margin-bottom: 50px; 3 | } 4 | 5 | 6 | .docContent img { 7 | display:block; 8 | margin: 50px auto 0; 9 | border: 1px solid; 10 | border-color: #cccccc; 11 | } 12 | 13 | 14 | .docContent figcaption { 15 | text-align: center; 16 | margin-bottom: 50px; 17 | } 18 | 19 | 20 | .docContent .docSection { 21 | padding-bottom: 25px; 22 | } 23 | 24 | 25 | .docContent table { 26 | font-size: 12px; 27 | } 28 | 29 | 30 | .docContent pre { 31 | text-align: center; 32 | } 33 | 34 | 35 | .docContent .tip { 36 | font-style: italic; 37 | background-color: #d9edf7; 38 | font-size: 12px; 39 | } 40 | 41 | .docContent .video { 42 | text-align: center; 43 | } 44 | -------------------------------------------------------------------------------- /db_templates/Java-JUnit/Root/src/Main.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Main class of the Java program. 3 | * 4 | */ 5 | 6 | public class Main { 7 | 8 | public static void main(String[] args) { 9 | 10 | // we print a heading and make it bigger using HTML formatting 11 | System.out.println("

-- Maximun Element Finder --

"); 12 | 13 | // create the finder and call the function to find the maximum element 14 | Finder myFinder = new Finder(); 15 | int[] myArray = new int[] {2, 3, 42, 12, 7}; 16 | int maxElement = myFinder.findMaximumElement(myArray); 17 | 18 | System.out.println("The maximum element is: " + maxElement); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /test/server/src_examples/java/j_error_several_files.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "Java", 3 | "files": [ 4 | { 5 | "filename": "Root/Application.java", 6 | "content": "public class Application { public static void main(String[] args) {B b = new B(); System.out.println(\"Hello Java Test-2 \"); }}" 7 | }, 8 | { 9 | "filename": "Root/C.java", 10 | "content": "public class C { public C() {System.out.println(\"Hello C\"); }}" 11 | }, 12 | { 13 | "filename": "Root/codeboard.json", 14 | "content": "{\n\t\"MainFileForCompilation\": \"Application.java\",\n\t\"MainClassForRunning\":\"Application\"\n}" 15 | } 16 | ], 17 | "action": "compile", 18 | "stream": false 19 | } -------------------------------------------------------------------------------- /test/server/src_examples/c/c_error_main.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "C", 3 | "files": [ 4 | { 5 | "filename": "Root/b.h", 6 | "content": "#ifndef B_MODULE\n #define B_MODULE\n int foo();\n #endif" 7 | }, 8 | { 9 | "filename": "Root/b.c", 10 | "content": "#include \"b.h\"\n#include \"c.h\"\n int foo () {bar(); return 1;}" 11 | }, 12 | { 13 | "filename": "Root/c.h", 14 | "content": "#ifndef C_MODULE\n #define C_MODULE\n int bar();\n #endif" 15 | }, 16 | { 17 | "filename": "Root/c.c", 18 | "content": "#include \n#include \"c.h\"\n int bar () {printf(\"Hello C\");return 2;}" 19 | } 20 | ], 21 | "action": "compile", 22 | "stream": false 23 | } -------------------------------------------------------------------------------- /test/server/src_examples/c/c_wrong_id2.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "Haskell", 3 | "files": [ 4 | { 5 | "filename": "Root/application.hs", 6 | "content": "import B(foo)\nimport C(bar)\n\nmain = do\n putStrLn \"Hello Haskell World!\"\n foo\n bar\n\n" 7 | }, 8 | { 9 | "filename": "Root/B.hs", 10 | "content": "module B (foo) where foo = do putStrLn \"Hello B\"" 11 | }, 12 | { 13 | "filename": "Root/C.hs", 14 | "content": "module C (bar) where bar = do putStrLn \"Hello C\"" 15 | }, 16 | { 17 | "filename": "Root/codeboard.json", 18 | "content": "{\n\t\"MainFileForCompilation\":\"application.hs\"\n}" 19 | } 20 | ], 21 | "action": "compile", 22 | "stream": false 23 | } -------------------------------------------------------------------------------- /test/server/src_examples/cpp/cpp_error_main.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "C++", 3 | "files": [ 4 | { 5 | "filename": "Root/b.h", 6 | "content": "#ifndef B_MODULE\n #define B_MODULE\n int foo();\n #endif" 7 | }, 8 | { 9 | "filename": "Root/b.cpp", 10 | "content": "#include \"b.h\"\n#include \"c.h\"\n int foo () {bar(); return 1;}" 11 | }, 12 | { 13 | "filename": "Root/c.h", 14 | "content": "#ifndef C_MODULE\n #define C_MODULE\n int bar();\n #endif" 15 | }, 16 | { 17 | "filename": "Root/c.cpp", 18 | "content": "#include \n#include \"c.h\"\n int bar () {std::cout << \"Hello C++ world!\" << std::endl;return 2;}" 19 | } 20 | ], 21 | "action": "compile", 22 | "stream": false 23 | } -------------------------------------------------------------------------------- /test/server/src_examples/haskell/hs_wrong_id2.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "Haskell", 3 | "files": [ 4 | { 5 | "filename": "Root/application.hs", 6 | "content": "import B(foo)\nimport C(bar)\n\nmain = do\n putStrLn \"Hello Haskell World!\"\n foo\n bar\n\n" 7 | }, 8 | { 9 | "filename": "Root/B.hs", 10 | "content": "module B (foo) where foo = do putStrLn \"Hello B\"" 11 | }, 12 | { 13 | "filename": "Root/C.hs", 14 | "content": "module C (bar) where bar = do putStrLn \"Hello C\"" 15 | }, 16 | { 17 | "filename": "Root/codeboard.json", 18 | "content": "{\n\t\"MainFileForCompilation\":\"application.hs\",\n\t\"GHCArgumentMainIs\":\"B.foo\"\n}" 19 | } 20 | ], 21 | "action": "compile", 22 | "stream": false 23 | } -------------------------------------------------------------------------------- /test/server/src_examples/haskell/hs_incremental2.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "Haskell", 3 | "files": [ 4 | { 5 | "filename": "Root/application.hs", 6 | "content": "import B(foo)\nimport C(bar)\n\nmain = do\n putStrLn \"Hello Haskell World!\"\n foo\n bar\n\n" 7 | }, 8 | { 9 | "filename": "Root/B.hs", 10 | "content": "module B (foo) where foo = do putStrLn \"Hello B\"" 11 | }, 12 | { 13 | "filename": "Root/C.hs", 14 | "content": "module C (bar) where bar = do putStrLn \"Hello C\"" 15 | }, 16 | { 17 | "filename": "Root/codeboard.json", 18 | "content": "{\n\t\"MainFileForCompilation\":\"application.hs\",\n\t\"GHCArgumentMainIs\":\"main\"\n}" 19 | } 20 | ], 21 | "action": "compile", 22 | "stream": false 23 | } -------------------------------------------------------------------------------- /test/server/src_examples/haskell/hs_several_files.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "Haskell", 3 | "files": [ 4 | { 5 | "filename": "Root/application.hs", 6 | "content": "import B(foo)\nimport C(bar)\n\nmain = do\n putStrLn \"Hello Haskell World!\"\n foo\n bar\n\n" 7 | }, 8 | { 9 | "filename": "Root/B.hs", 10 | "content": "module B (foo) where foo = do putStrLn \"Hello B\"" 11 | }, 12 | { 13 | "filename": "Root/C.hs", 14 | "content": "module C (bar) where bar = do putStrLn \"Hello C\"" 15 | }, 16 | { 17 | "filename": "Root/codeboard.json", 18 | "content": "{\n\t\"MainFileForCompilation\":\"application.hs\",\n\t\"GHCArgumentMainIs\":\"main\"\n}" 19 | } 20 | ], 21 | "action": "compile", 22 | "stream": false 23 | } -------------------------------------------------------------------------------- /test/server/src_examples/haskell/hs_run_several_files.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "Haskell", 3 | "files": [ 4 | { 5 | "filename": "Root/application.hs", 6 | "content": "import B(foo)\nimport C(bar)\n\nmain = do\n putStrLn \"Hello Haskell World!\"\n foo\n bar\n\n" 7 | }, 8 | { 9 | "filename": "Root/B.hs", 10 | "content": "module B (foo) where foo = do putStrLn \"Hello B\"" 11 | }, 12 | { 13 | "filename": "Root/C.hs", 14 | "content": "module C (bar) where bar = do putStrLn \"Hello C\"" 15 | }, 16 | { 17 | "filename": "Root/codeboard.json", 18 | "content": "{\n\t\"MainFileForCompilation\":\"application.hs\",\n\t\"GHCArgumentMainIs\":\"main\"\n}" 19 | } 20 | ], 21 | "action": "compile", 22 | "stream": false 23 | } -------------------------------------------------------------------------------- /lib/models/file.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by haches on 7/7/14. 3 | * 4 | * The ORM model for a file. 5 | */ 6 | 7 | 8 | module.exports = function(sequelize, DataTypes) { 9 | var File = sequelize.define( 10 | 'File', 11 | { 12 | filename: DataTypes.STRING, 13 | path: DataTypes.STRING, 14 | uniqueId: DataTypes.INTEGER, 15 | parentUId: DataTypes.INTEGER, 16 | isFolder: DataTypes.BOOLEAN, 17 | content: {type: 'MEDIUMTEXT'}, 18 | isHidden: {type: DataTypes.BOOLEAN, defaultValue: false} 19 | }, 20 | { 21 | classMethods: { 22 | associate: function(models) { 23 | File.belongsTo(models.Project, {foreignKeyConstraint: true, onDelete: 'CASCADE'}); 24 | } 25 | } 26 | } 27 | ); 28 | 29 | return File; 30 | }; 31 | -------------------------------------------------------------------------------- /app/scripts/directives/ngSelectOnFocus.js: -------------------------------------------------------------------------------- 1 | /** 2 | * A directive to select the text of an input element 3 | * when the input element gets the focus. 4 | * 5 | * Created by hce on 24/09/15. 6 | */ 7 | 8 | 'use strict'; 9 | 10 | angular.module('codeboardApp') 11 | .directive('ngSelectOnFocus', ['$timeout', function ($timeout) { 12 | return { 13 | restrict: 'A', 14 | link: function (scope, element, attrs) { 15 | var focusedElement = null; 16 | 17 | element.on('focus', function () { 18 | var self = this; 19 | // timeout is sometimes needed to let the browser finish rendering 20 | // only then can we set a focus 21 | $timeout(function () { 22 | self.select(); 23 | }, 10); 24 | }); 25 | } 26 | } 27 | }]); -------------------------------------------------------------------------------- /test/server/src_examples/python/py_several_files_folder.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "Python", 3 | "files": [ 4 | { 5 | "filename": "Root/application.py", 6 | "content": "from p1.b import foo\nfrom p1.c import bar\nfoo()\nbar()\nprint \"Goodbye, World!\"" 7 | }, 8 | { 9 | "filename": "Root/p1/__init__.py", 10 | "content": " " 11 | }, 12 | { 13 | "filename": "Root/p1/b.py", 14 | "content": "def foo():\n\tprint \"Goodbye, P1.foo!\"" 15 | }, 16 | { 17 | "filename": "Root/p1/c.py", 18 | "content": "def bar():\n\tprint \"Goodbye, P1.bar!\"" 19 | }, 20 | { 21 | "filename": "Root/codeboard.json", 22 | "content": "{\n\t\"MainFileForRunning\":\"application.py\"\n}" 23 | } 24 | ], 25 | "action": "compile", 26 | "stream": false 27 | } -------------------------------------------------------------------------------- /app/views/partials/404.html: -------------------------------------------------------------------------------- 1 | 23 | 24 |
25 |
26 |

Codeboard.io

27 |
28 |

Error 404

29 |

Sorry, the page you're looking for does not exist.

30 |

31 | Okay, take me home 32 |

33 |
34 |
35 |
-------------------------------------------------------------------------------- /app/views/partials/401.html: -------------------------------------------------------------------------------- 1 | 23 | 24 |
25 |
26 |

Codeboard.io

27 |
28 |

Error 401

29 |

Sorry, you're not authorized to access this page.

30 |

31 | Okay, take me home 32 |

33 |
34 |
35 |
36 | -------------------------------------------------------------------------------- /app/views/partials/navbar.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 | 6 |
7 | 16 |
17 |
18 |
19 |
20 | -------------------------------------------------------------------------------- /test/server/src_examples/java/j_wrong_id2.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "Java", 3 | "files": [ 4 | { 5 | "filename": "Root/Application.java", 6 | "content": "public class Application { public static void main(String[] args) {B b = new B(); System.out.println(\"Hello Java Test-2 \"); }}" 7 | }, 8 | { 9 | "filename": "Root/B.java", 10 | "content": "public class B { public B() {C c = new C(); System.out.println(\"Hello B\"); }}" 11 | }, 12 | { 13 | "filename": "Root/C.java", 14 | "content": "public class C { public C() {System.out.println(\"Hello C\"); }}" 15 | }, 16 | { 17 | "filename": "Root/codeboard.json", 18 | "content": "{\n\t\"MainFileForCompilation\": \"Application.java\",\n\t\"MainClassForRunning\":\"Application\"\n}" 19 | } 20 | ], 21 | "action": "compile", 22 | "stream": false 23 | } -------------------------------------------------------------------------------- /test/server/src_examples/java/j_incremental2.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "Java", 3 | "files": [ 4 | { 5 | "filename": "Root/Application.java", 6 | "content": "public class Application { public static void main(String[] args) {B b = new B(); System.out.println(\"Hello Java Test-2 \"); }}" 7 | }, 8 | { 9 | "filename": "Root/B.java", 10 | "content": "public class B { public B() {C c = new C(); System.out.println(\"Hello B\"); }}" 11 | }, 12 | { 13 | "filename": "Root/C.java", 14 | "content": "public class C { public C() {System.out.println(\"Hello C\"); }}" 15 | }, 16 | { 17 | "filename": "Root/codeboard.json", 18 | "content": "{\n\t\"MainFileForCompilation\": \"Application.java\",\n\t\"MainClassForRunning\":\"Application\"\n}" 19 | } 20 | ], 21 | "action": "compile", 22 | "stream": false 23 | } -------------------------------------------------------------------------------- /test/server/src_examples/java/j_several_files.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "Java", 3 | "files": [ 4 | { 5 | "filename": "Root/Application.java", 6 | "content": "public class Application { public static void main(String[] args) {B b = new B(); System.out.println(\"Hello Java Test-2 \"); }}" 7 | }, 8 | { 9 | "filename": "Root/B.java", 10 | "content": "public class B { public B() {C c = new C(); System.out.println(\"Hello B\"); }}" 11 | }, 12 | { 13 | "filename": "Root/C.java", 14 | "content": "public class C { public C() {System.out.println(\"Hello C\"); }}" 15 | }, 16 | { 17 | "filename": "Root/codeboard.json", 18 | "content": "{\n\t\"MainFileForCompilation\": \"Application.java\",\n\t\"MainClassForRunning\":\"Application\"\n}" 19 | } 20 | ], 21 | "action": "compile", 22 | "stream": false 23 | } -------------------------------------------------------------------------------- /db_templates/Python-UnitTest/Root/test/finderTest.py: -------------------------------------------------------------------------------- 1 | ## 2 | # Tests for finder.py 3 | # 4 | # All tests in the folder "test" are executed 5 | # when the "Test" action is invoked. 6 | # 7 | ## 8 | 9 | from Root.src.finder import maximum_in_list 10 | import unittest 11 | 12 | class finderTest(unittest.TestCase): 13 | 14 | # test with a list sorted in ascending order 15 | def test_ascending_input(self): 16 | self.assertEqual(maximum_in_list([1, 2, 3, 4, 5]), 5) 17 | 18 | # test with a list sorted in descending order 19 | def test_descending_input(self): 20 | self.assertEqual(maximum_in_list([117, 56, 38, 11, 0]), 117) 21 | 22 | # test with a randomly sorted list 23 | def test_random_input(self): 24 | self.assertEqual(maximum_in_list([42, 11, 38, 75, 14]), 75) 25 | 26 | 27 | if __name__ == '__main__': 28 | unittest.main() 29 | -------------------------------------------------------------------------------- /lib/services/userSrv.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by haches on 7/27/14. 3 | * 4 | * This service module provides a number of 5 | * utility functions for user data stored 6 | * in the database. 7 | */ 8 | 9 | 'use strict'; 10 | 11 | 12 | var db = require('../models'); 13 | 14 | 15 | /** 16 | * Returns a promise that resolves to the user 17 | * with the given username (might be null if no entry of with that username exists). 18 | * @param username for which username the user should be returned 19 | * @param attributes the attributes of that user that should be returned 20 | * @returns {*|Object|Mixed} promise resolving to a user 21 | */ 22 | var getUser = function(username, attributes) { 23 | 24 | return db.User.find( 25 | { 26 | where: {username: username}, 27 | attributes: attributes 28 | } 29 | ); 30 | }; 31 | 32 | 33 | exports.getUser = getUser; -------------------------------------------------------------------------------- /test/server/src_examples/java/j_run_several_files.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "Java", 3 | "files": [ 4 | { 5 | "filename": "Root/Application.java", 6 | "content": "public class Application { public static void main(String[] args) {B b = new B(); System.out.println(\"Hello Java Test-2 \"); }}" 7 | }, 8 | { 9 | "filename": "Root/B.java", 10 | "content": "public class B { public B() {C c = new C(); System.out.println(\"Hello B\"); }}" 11 | }, 12 | { 13 | "filename": "Root/C.java", 14 | "content": "public class C { public C() {System.out.println(\"Hello C\"); }}" 15 | }, 16 | { 17 | "filename": "Root/codeboard.json", 18 | "content": "{\n\t\"MainFileForCompilation\": \"Application.java\",\n\t\"MainClassForRunning\":\"Application\"\n}" 19 | } 20 | ], 21 | "action": "compile", 22 | "stream": false 23 | } -------------------------------------------------------------------------------- /app/views/partials/usersAll.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |
5 | 6 |
7 |
8 |

{{users.length}} users

9 |
10 |
11 | 12 |
13 |
14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 |
UsernameJoined
{{user.username}}{{user.createdAt | date}}
28 |
29 |
30 |
31 |
32 | 33 | -------------------------------------------------------------------------------- /test/server/src_examples/c/c_several_files.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "C", 3 | "files": [ 4 | { 5 | "filename": "Root/application.c", 6 | "content": "#include \n#include \"b.h\"\n int main() { printf(\"Hello, C World! \"); foo(); \n\treturn 0; }" 7 | }, 8 | { 9 | "filename": "Root/b.h", 10 | "content": "#ifndef B_MODULE\n #define B_MODULE\n int foo();\n #endif" 11 | }, 12 | { 13 | "filename": "Root/b.c", 14 | "content": "#include \"b.h\"\n#include \"c.h\"\n int foo () {bar(); return 1;}" 15 | }, 16 | { 17 | "filename": "Root/c.h", 18 | "content": "#ifndef C_MODULE\n #define C_MODULE\n int bar();\n #endif" 19 | }, 20 | { 21 | "filename": "Root/c.c", 22 | "content": "#include \n#include \"c.h\"\n int bar () {printf(\"Hello C\");return 2;}" 23 | } 24 | ], 25 | "action": "compile", 26 | "stream": false 27 | } -------------------------------------------------------------------------------- /db_templates/Haskell-HSpec/Root/Test/FinderSpec.hs: -------------------------------------------------------------------------------- 1 | -- Tests for the Root.Src.Finder module. 2 | -- 3 | -- All tests in the folder "Test" are executed 4 | -- when the "Test" action is invoked. 5 | 6 | module Root.Test.FinderSpec where 7 | 8 | import Root.Src.Finder 9 | import Test.Hspec 10 | import Test.QuickCheck 11 | import Control.Exception (evaluate) 12 | 13 | main = hspec spec 14 | 15 | spec::Spec 16 | spec = do 17 | describe "Finder Specs: returns the maximum element of a list" $ do 18 | it "Test input with ascending order" $ do 19 | maxFunction [1, 2, 3, 4, 5] `shouldBe` (5 :: Int) 20 | it "Test input with descending order" $ do 21 | maxFunction [117, 56, 38, 11, 0] `shouldBe` (117 :: Int) 22 | it "Test input with random order" $ do 23 | maxFunction [42, 11, 38, 75, 14] `shouldBe` (75 :: Int) 24 | -------------------------------------------------------------------------------- /app/scripts/resources/userRes.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by hce on 7/26/14. 3 | * 4 | * Resources for functionality that is linked to the user. 5 | * 6 | */ 7 | 8 | 'use strict' 9 | 10 | 11 | angular.module('codeboardApp') 12 | 13 | .factory('UserRes', ['$resource', function($resource) { 14 | return $resource( 15 | '/api/users/:username', 16 | {username: '@username'} // when doing non-post request, the :username is filled in through the id property of the user-object 17 | ); 18 | }]) 19 | 20 | .factory('UserResSettings', ['$resource', function($resource) { 21 | return $resource( 22 | '/api/users/:username/settings', 23 | { 24 | username: '@username' 25 | }, 26 | { 27 | update: {method: 'PUT'} 28 | } 29 | ); 30 | }]) 31 | 32 | .factory('UsersAllRes', ['$resource', function($resource) { 33 | return $resource( 34 | '/api/users/' 35 | ); 36 | }]) 37 | -------------------------------------------------------------------------------- /test/server/src_examples/c/c_incremental2.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "C", 3 | "files": [ 4 | { 5 | "filename": "Root/application.c", 6 | "content": "#include \n#include \"./p1/b.h\"\n int main() { printf(\"Hello, C World! \"); \n\tfoo(); return 0; }" 7 | }, 8 | { 9 | "filename": "Root/p1/b.h", 10 | "content": "#ifndef B_MODULE\n #define B_MODULE\n int foo();\n #endif" 11 | }, 12 | { 13 | "filename": "Root/p1/b.c", 14 | "content": "#include \"b.h\"\n#include \"../p2/c.h\"\n int foo () {bar(); return 1;}" 15 | }, 16 | { 17 | "filename": "Root/p2/c.h", 18 | "content": "#ifndef C_MODULE\n #define C_MODULE\n int bar();\n #endif" 19 | }, 20 | { 21 | "filename": "Root/p2/c.c", 22 | "content": "#include \n#include \"c.h\"\n int bar () {printf(\"Hello C\"); return 2;}" 23 | } 24 | ], 25 | "action": "compile", 26 | "stream": false 27 | } -------------------------------------------------------------------------------- /test/server/src_examples/c/c_run_several_files.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "C", 3 | "files": [ 4 | { 5 | "filename": "Root/application.c", 6 | "content": "#include \n#include \"./p1/b.h\"\n int main() { printf(\"Hello, C World! \"); \n\tfoo(); return 0; }" 7 | }, 8 | { 9 | "filename": "Root/p1/b.h", 10 | "content": "#ifndef B_MODULE\n #define B_MODULE\n int foo();\n #endif" 11 | }, 12 | { 13 | "filename": "Root/p1/b.c", 14 | "content": "#include \"b.h\"\n#include \"../p2/c.h\"\n int foo () {bar(); return 1;}" 15 | }, 16 | { 17 | "filename": "Root/p2/c.h", 18 | "content": "#ifndef C_MODULE\n #define C_MODULE\n int bar();\n #endif" 19 | }, 20 | { 21 | "filename": "Root/p2/c.c", 22 | "content": "#include \n#include \"c.h\"\n int bar () {printf(\"Hello C\"); return 2;}" 23 | } 24 | ], 25 | "action": "compile", 26 | "stream": false 27 | } -------------------------------------------------------------------------------- /test/server/src_examples/c/c_several_files_folders.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "C", 3 | "files": [ 4 | { 5 | "filename": "Root/application.c", 6 | "content": "#include \n#include \"./p1/b.h\"\n int main() { printf(\"Hello, C World! \"); \n\tfoo(); return 0; }" 7 | }, 8 | { 9 | "filename": "Root/p1/b.h", 10 | "content": "#ifndef B_MODULE\n #define B_MODULE\n int foo();\n #endif" 11 | }, 12 | { 13 | "filename": "Root/p1/b.c", 14 | "content": "#include \"b.h\"\n#include \"../p2/c.h\"\n int foo () {bar(); return 1;}" 15 | }, 16 | { 17 | "filename": "Root/p2/c.h", 18 | "content": "#ifndef C_MODULE\n #define C_MODULE\n int bar();\n #endif" 19 | }, 20 | { 21 | "filename": "Root/p2/c.c", 22 | "content": "#include \n#include \"c.h\"\n int bar () {printf(\"Hello C\"); return 2;}" 23 | } 24 | ], 25 | "action": "compile", 26 | "stream": false 27 | } -------------------------------------------------------------------------------- /test/server/src_examples/haskell/hs_several_files_folders.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "Haskell", 3 | "files": [ 4 | { 5 | "filename": "Root/application.hs", 6 | "content": "import P1(ff)\nimport P1.B(foo)\nimport P1.C(bar)\n\nmain = do\n putStrLn \"Hello Haskell World!\"\n foo\n bar\n\n" 7 | }, 8 | { 9 | "filename": "Root/P1.hs", 10 | "content": "module P1 (ff) where ff = do putStrLn \"Hello P1\"" 11 | }, 12 | { 13 | "filename": "Root/P1/B.hs", 14 | "content": "module P1.B (foo) where foo = do putStrLn \"Hello P1.B\"" 15 | }, 16 | { 17 | "filename": "Root/P1/C.hs", 18 | "content": "module P1.C (bar) where bar = do putStrLn \"Hello P1.C\"" 19 | }, 20 | { 21 | "filename": "Root/codeboard.json", 22 | "content": "{\n\t\"MainFileForCompilation\":\"application.hs\",\n\t\"GHCArgumentMainIs\":\"main\"\n}" 23 | } 24 | ], 25 | "action": "compile", 26 | "stream": false 27 | } -------------------------------------------------------------------------------- /test/server/src_examples/haskell/hs_run_several_files_folder.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "Haskell", 3 | "files": [ 4 | { 5 | "filename": "Root/application.hs", 6 | "content": "import P1(ff)\nimport P1.B(foo)\nimport P1.C(bar)\n\nmain = do\n putStrLn \"Hello Haskell World!\"\n foo\n bar\n\n" 7 | }, 8 | { 9 | "filename": "Root/P1.hs", 10 | "content": "module P1 (ff) where ff = do putStrLn \"Hello P1\"" 11 | }, 12 | { 13 | "filename": "Root/P1/B.hs", 14 | "content": "module P1.B (foo) where foo = do putStrLn \"Hello P1.B\"" 15 | }, 16 | { 17 | "filename": "Root/P1/C.hs", 18 | "content": "module P1.C (bar) where bar = do putStrLn \"Hello P1.C\"" 19 | }, 20 | { 21 | "filename": "Root/codeboard.json", 22 | "content": "{\n\t\"MainFileForCompilation\":\"application.hs\",\n\t\"GHCArgumentMainIs\":\"main\"\n}" 23 | } 24 | ], 25 | "action": "compile", 26 | "stream": false 27 | } -------------------------------------------------------------------------------- /test/server/src_examples/cpp/cpp_several_files.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "C++", 3 | "files": [ 4 | { 5 | "filename": "Root/application.cpp", 6 | "content": "#include \n#include \"b.h\"\n int main() { std::cout << \"Hello C++ world!\" << std::endl; foo(); \n\treturn 0; }" 7 | }, 8 | { 9 | "filename": "Root/b.h", 10 | "content": "#ifndef B_MODULE\n #define B_MODULE\n int foo();\n #endif" 11 | }, 12 | { 13 | "filename": "Root/b.cpp", 14 | "content": "#include \"b.h\"\n#include \"c.h\"\n int foo () {bar(); return 1;}" 15 | }, 16 | { 17 | "filename": "Root/c.h", 18 | "content": "#ifndef C_MODULE\n #define C_MODULE\n int bar();\n #endif" 19 | }, 20 | { 21 | "filename": "Root/c.cpp", 22 | "content": "#include \n#include \"c.h\"\n int bar () {std::cout << \"Hello C++ world!\" << std::endl;return 2;}" 23 | } 24 | ], 25 | "action": "compile", 26 | "stream": false 27 | } -------------------------------------------------------------------------------- /test/server/src_examples/cpp/cpp_incremental2.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "C++", 3 | "files": [ 4 | { 5 | "filename": "Root/application.cpp", 6 | "content": "#include \n#include \"./p1/b.h\"\n int main() { std::cout << \"Hello C++ world!\" << std::endl; \n\tfoo(); return 0; }" 7 | }, 8 | { 9 | "filename": "Root/p1/b.h", 10 | "content": "#ifndef B_MODULE\n #define B_MODULE\n int foo();\n #endif" 11 | }, 12 | { 13 | "filename": "Root/p1/b.cpp", 14 | "content": "#include \"b.h\"\n#include \"../p2/c.h\"\n int foo () {bar(); return 1;}" 15 | }, 16 | { 17 | "filename": "Root/p2/c.h", 18 | "content": "#ifndef C_MODULE\n #define C_MODULE\n int bar();\n #endif" 19 | }, 20 | { 21 | "filename": "Root/p2/c.cpp", 22 | "content": "#include \n#include \"c.h\"\n int bar () {std::cout << \"Hello C\" << std::endl; return 2;}" 23 | } 24 | ], 25 | "action": "compile", 26 | "stream": false 27 | } -------------------------------------------------------------------------------- /test/server/src_examples/cpp/cpp_wrong_id2.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "C++", 3 | "files": [ 4 | { 5 | "filename": "Root/application.cpp", 6 | "content": "#include \n#include \"./p1/b.h\"\n int main() { std::cout << \"Hello C++ world!\" << std::endl; \n\tfoo(); return 0; }" 7 | }, 8 | { 9 | "filename": "Root/p1/b.h", 10 | "content": "#ifndef B_MODULE\n #define B_MODULE\n int foo();\n #endif" 11 | }, 12 | { 13 | "filename": "Root/p1/b.cpp", 14 | "content": "#include \"b.h\"\n#include \"../p2/c.h\"\n int foo () {bar(); return 1;}" 15 | }, 16 | { 17 | "filename": "Root/p2/c.h", 18 | "content": "#ifndef C_MODULE\n #define C_MODULE\n int bar();\n #endif" 19 | }, 20 | { 21 | "filename": "Root/p2/c.cpp", 22 | "content": "#include \n#include \"c.h\"\n int bar () {std::cout << \"Hello C\" << std::endl; return 2;}" 23 | } 24 | ], 25 | "action": "compile", 26 | "stream": false 27 | } -------------------------------------------------------------------------------- /test/server/src_examples/cpp/cpp_run_several_files.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "C++", 3 | "files": [ 4 | { 5 | "filename": "Root/application.cpp", 6 | "content": "#include \n#include \"./p1/b.h\"\n int main() { std::cout << \"Hello C++ world!\" << std::endl; \n\tfoo(); return 0; }" 7 | }, 8 | { 9 | "filename": "Root/p1/b.h", 10 | "content": "#ifndef B_MODULE\n #define B_MODULE\n int foo();\n #endif" 11 | }, 12 | { 13 | "filename": "Root/p1/b.cpp", 14 | "content": "#include \"b.h\"\n#include \"../p2/c.h\"\n int foo () {bar(); return 1;}" 15 | }, 16 | { 17 | "filename": "Root/p2/c.h", 18 | "content": "#ifndef C_MODULE\n #define C_MODULE\n int bar();\n #endif" 19 | }, 20 | { 21 | "filename": "Root/p2/c.cpp", 22 | "content": "#include \n#include \"c.h\"\n int bar () {std::cout << \"Hello C\" << std::endl; return 2;}" 23 | } 24 | ], 25 | "action": "compile", 26 | "stream": false 27 | } -------------------------------------------------------------------------------- /test/server/src_examples/cpp/cpp_several_files_folders.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "C++", 3 | "files": [ 4 | { 5 | "filename": "Root/application.cpp", 6 | "content": "#include \n#include \"./p1/b.h\"\n int main() { std::cout << \"Hello C++ world!\" << std::endl; \n\tfoo(); return 0; }" 7 | }, 8 | { 9 | "filename": "Root/p1/b.h", 10 | "content": "#ifndef B_MODULE\n #define B_MODULE\n int foo();\n #endif" 11 | }, 12 | { 13 | "filename": "Root/p1/b.cpp", 14 | "content": "#include \"b.h\"\n#include \"../p2/c.h\"\n int foo () {bar(); return 1;}" 15 | }, 16 | { 17 | "filename": "Root/p2/c.h", 18 | "content": "#ifndef C_MODULE\n #define C_MODULE\n int bar();\n #endif" 19 | }, 20 | { 21 | "filename": "Root/p2/c.cpp", 22 | "content": "#include \n#include \"c.h\"\n int bar () {std::cout << \"Hello C\" << std::endl; return 2;}" 23 | } 24 | ], 25 | "action": "compile", 26 | "stream": false 27 | } -------------------------------------------------------------------------------- /app/scripts/resources/projectRes.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('codeboardApp') 4 | 5 | .factory('ProjectSettingsRes', ['$resource', function($resource) { 6 | return $resource( 7 | '/api/projects/:projectId/settings', 8 | {projectId: '@id'} // when doing non-post request, the :projectId is filled in through the id property of the project-object 9 | ); 10 | }]) 11 | 12 | .factory('ProjectSummaryRes', ['$resource', function($resource) { 13 | return $resource( 14 | '/api/projects/:projectId/summary', 15 | {projectId: '@id'} 16 | ); 17 | }]) 18 | 19 | .factory('ProjectSubmissionRes', ['$resource', function($resource) { 20 | return $resource( 21 | '/api/projects/:projectId/submissions', 22 | {projectId: '@id'} 23 | ); 24 | }]) 25 | 26 | .factory('ProjectRes', ['$resource', function($resource) { 27 | return $resource( 28 | '/api/projects/:projectId', 29 | {projectId: '@id'}, 30 | {update: {method: 'PUT'}} 31 | ); 32 | }]) 33 | -------------------------------------------------------------------------------- /app/scripts/controllers/navbarCtrl.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('codeboardApp') 4 | .controller('NavbarCtrl', ['$scope', '$location', 'UserSrv', 5 | function ($scope, $location, UserSrv) { 6 | 7 | $scope.username = UserSrv.getUsername(); 8 | 9 | $scope.isAuth = UserSrv.isAuthenticated(); 10 | 11 | 12 | $scope.$on('userLoggedIn', function(event, args) { 13 | $scope.username = UserSrv.getUsername(); 14 | $scope.isAuth = UserSrv.isAuthenticated(); 15 | }); 16 | 17 | 18 | $scope.signOut = function() { 19 | 20 | UserSrv.signOutUser(); 21 | 22 | // console.log('Trying to log out'); 23 | // 24 | // $http.delete('/api/session').success( 25 | // function(data, status, header, config) { 26 | // $rootScope.currentUser = null; 27 | // $location.path('/'); // send the user back to the home page 28 | // console.log('user logged out: ' + data); 29 | // } 30 | // ).error(function(err) { 31 | // console.log(err); 32 | // }) 33 | } 34 | }]); 35 | -------------------------------------------------------------------------------- /app/scripts/controllers/projectSummaryCtrl.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Created by haches on 14.11.2014. 5 | * 6 | * Controller for the summary page of a project. 7 | * 8 | */ 9 | 10 | angular.module('codeboardApp') 11 | .controller('ProjectSummaryCtrl', ['$scope', '$http', '$log', '$routeParams', '$location', 'projectSummaryData', 'UserSrv', 12 | function($scope, $http, $log, $routeParams, $location, projectSummaryData, UserSrv) { 13 | 14 | $scope.prj = projectSummaryData; 15 | 16 | /** 17 | * Checks if the current user is an owner of the project for which the summary is displayed. 18 | * @return true if the current user is a) authenticated and b) an owner of the project 19 | */ 20 | $scope.isCurrentUserProjectOwner = function() { 21 | return UserSrv.isAuthenticated() && projectSummaryData.ownerSet.some( 22 | function(element, index, array) { 23 | return element.username === UserSrv.getUsername(); 24 | } 25 | ); 26 | }; 27 | 28 | }]); 29 | -------------------------------------------------------------------------------- /lib/models/ltiSession.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by hce on 9/7/14. 3 | * 4 | * Model to store session information when a request over LTI comes in. 5 | * An typical LTI (post) request contains information about the user_id, 6 | * callback url etc. 7 | */ 8 | 9 | 10 | module.exports = function(sequelize, DataTypes) { 11 | var LtiSession = sequelize.define( 12 | 'LtiSession', 13 | { 14 | userId: DataTypes.STRING, 15 | lisResultSourcedid: DataTypes.STRING, 16 | lisOutcomeServiceUrl: DataTypes.STRING, 17 | oauthNonce: DataTypes.STRING, 18 | oauthTimestamp: DataTypes.STRING, 19 | oauthConsumerKey: DataTypes.STRING, 20 | oauthSignatureMethod: DataTypes.STRING, 21 | oauthVersion: DataTypes.STRING, 22 | oauthSignature: DataTypes.STRING 23 | }, 24 | { 25 | classMethods: { 26 | associate: function(models) { 27 | LtiSession.belongsTo(models.Project, {onDelete: 'SET NULL', onUpdate: 'CASCADE'}); 28 | } 29 | } 30 | } 31 | ); 32 | 33 | return LtiSession; 34 | }; 35 | -------------------------------------------------------------------------------- /lib/models/templateFile.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by haches on 7/25/14. 3 | * 4 | * The ORM model for templates of files. 5 | * This is used by the templates of projects. 6 | * 7 | */ 8 | 9 | module.exports = function(sequelize, DataTypes) { 10 | 11 | var templateFile = sequelize.define( 12 | 'TemplateFile', 13 | { 14 | // name of the file 15 | filename: DataTypes.STRING, 16 | 17 | // the relative path of the file (without the filename) 18 | path: DataTypes.STRING, 19 | 20 | // an id that is unique to this file within the scope of the project 21 | uniqueId: DataTypes.INTEGER, 22 | 23 | // the id of the parent folder (-1 if it's the root folder) 24 | parentUId: DataTypes.INTEGER, 25 | 26 | // boolean value 27 | isFolder: DataTypes.BOOLEAN, 28 | 29 | // the content of the file 30 | content: DataTypes.TEXT, 31 | 32 | // true if the file is hidden from users and only visible to owners of the project 33 | isHidden: DataTypes.BOOLEAN 34 | } 35 | ); 36 | 37 | return templateFile; 38 | }; 39 | -------------------------------------------------------------------------------- /db_templates/Java-JUnit/Root/src/Finder.java: -------------------------------------------------------------------------------- 1 | /** 2 | * This class provides functions to search in arrays. 3 | * 4 | */ 5 | 6 | public class Finder { 7 | 8 | /** 9 | * Finds the maximum element in an integer array. 10 | * @param input the array to search in 11 | * @return the maximum element of input 12 | */ 13 | public int findMaximumElement(int[] input) { 14 | 15 | // Your task: 16 | // - Check if this function works for all possible integers. 17 | // - Throw an Error object with message "Array is empty." 18 | // if the input array is empty. 19 | 20 | int maxElement = 0; 21 | 22 | // loop through the array and look at each element 23 | for (int i = 0; i < input.length; i++) { 24 | if (maxElement < input[i]) { 25 | // current array element is greater than any we've seen before 26 | // so we store it as the new maximum element 27 | maxElement = input[i]; 28 | } 29 | } 30 | 31 | return maxElement; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /db_templates/Python-UnitTest/Root/testSubmission/subTest.py: -------------------------------------------------------------------------------- 1 | ## 2 | # Tests used to check a submission. 3 | # 4 | # All tests in the "test_submission" folder are used for 5 | # checking a submission and are executed when the 6 | # "Submission" action is invoked. 7 | # 8 | ## 9 | 10 | from Root.src.main import maximum_in_list 11 | import sys 12 | import unittest 13 | 14 | class subTest(unittest.TestCase): 15 | 16 | # test with randomly ordered elements in the list 17 | def test_unsorted_input(self): 18 | self.assertEqual(maximum_in_list([115, 54, 3, 0, 76, 665]), 665) 19 | 20 | # test with negative elements in the list 21 | def test_negative_inputs(self): 22 | self.assertEqual(maximum_in_list([-11, -55, -1, -12]), -1) 23 | 24 | # test with a large element in the list 25 | def test_max_number(self): 26 | self.assertEqual(maximum_in_list([-17, 216, sys.maxsize]), sys.maxsize) 27 | 28 | # test if a ValueError exception is raised when providing an empty list 29 | def test_empty_list(self): 30 | self.assertRaises(ValueError, maximum_in_list, []) 31 | 32 | 33 | if __name__ == '__main__': 34 | unittest.main() 35 | -------------------------------------------------------------------------------- /app/components/angularTreeview/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Steve 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 ETH Zurich; H.-Christian Estler, Martin Nordio 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /lib/models/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Author: haches 4 | * 5 | * This code holds the configuration for the DB. 6 | * It also allows to load all model files that exist 7 | * in the folder 'models'. 8 | * 9 | * The models can afterwards be accesses using db.ModelName 10 | * 11 | */ 12 | 13 | var fs = require('fs'), 14 | path = require('path'), 15 | Sequelize = require('sequelize'), 16 | lodash = require('lodash'), 17 | config = require('../config/config.js'), 18 | sequelize = new Sequelize(config.db.database, config.db.username, config.db.password, {host: config.db.host, port: config.db.port, logging: false}), 19 | db = {}; 20 | 21 | fs 22 | .readdirSync(__dirname) 23 | .filter(function(file) { 24 | return (file.indexOf('.') !== 0) && (file !== 'index.js'); 25 | }) 26 | .forEach(function(file) { 27 | var model = sequelize.import(path.join(__dirname, file)); 28 | db[model.name] = model; 29 | }); 30 | 31 | Object.keys(db).forEach(function(modelName) { 32 | if ('associate' in db[modelName]) { 33 | db[modelName].associate(db); 34 | } 35 | }); 36 | 37 | module.exports = lodash.extend({ 38 | sequelize: sequelize, 39 | Sequelize: Sequelize 40 | }, db); 41 | -------------------------------------------------------------------------------- /db_templates/Haskell-HSpec/Root/TestSubmission/SubSpec.hs: -------------------------------------------------------------------------------- 1 | -- Tests used to check a submission. By default we set this 2 | -- file to hidden (h) so students won't see these test cases. 3 | -- 4 | -- All tests in the "TestSubmission" folder are used for 5 | -- checking a submission and are executed when the 6 | -- "Submission" action is invoked. 7 | 8 | module Root.Test.SubSpec where 9 | 10 | import Root.Src.Finder 11 | import Test.Hspec 12 | import Test.QuickCheck 13 | import Control.Exception (evaluate) 14 | 15 | main = hspec spec 16 | 17 | spec::Spec 18 | spec = do 19 | describe "Finder Specs: returns the maximum element of a list" $ do 20 | it "Test input with ascending order" $ do 21 | maxFunction [1, 2, 5, 44, 333] `shouldBe` (333 :: Int) 22 | it "Test input with descending order" $ do 23 | maxFunction [435, 33, 5, 1] `shouldBe` (435 :: Int) 24 | it "Test input with random order" $ do 25 | maxFunction [8, 2, 45, 77, 33, 5, 10] `shouldBe` (77 :: Int) 26 | it "Test input with negative numbers" $ do 27 | maxFunction [-8, -100, -45, -77, -33, -5, -10] `shouldBe` (-5 :: Int) 28 | -------------------------------------------------------------------------------- /test/server/src_examples/java/j_several_files_folders.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "Java", 3 | "files": [ 4 | { 5 | "filename": "Root/Application.java", 6 | "content": "import p1.*; import p2.*; public class Application { public static void main(String[] args) {B b = new B(); D d = new D(); E e = new E(); System.out.println(\"Hello Java Test-3 \"); }}" 7 | }, 8 | { 9 | "filename": "Root/p1/B.java", 10 | "content": "package p1; public class B { public B() {C c = new C(); System.out.println(\"Hello B\"); }}" 11 | }, 12 | { 13 | "filename": "Root/p1/C.java", 14 | "content": "package p1; public class C { public C() {System.out.println(\"Hello C\"); }}" 15 | }, 16 | { 17 | "filename": "Root/p2/D.java", 18 | "content": "package p2; public class D { public D() {System.out.println(\"Hello D\"); }}" 19 | }, 20 | { 21 | "filename": "Root/p2/E.java", 22 | "content": "package p2; public class E { public E() {System.out.println(\"Hello E\"); }}" 23 | }, 24 | { 25 | "filename": "Root/codeboard.json", 26 | "content": "{\n\t\"MainFileForCompilation\": \"Application.java\",\n\t\"MainClassForRunning\":\"Application\"\n}" 27 | } 28 | ], 29 | "action": "compile", 30 | "stream": false 31 | } -------------------------------------------------------------------------------- /test/server/src_examples/java/j_run_several_files_folder.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "Java", 3 | "files": [ 4 | { 5 | "filename": "Root/Application.java", 6 | "content": "import p1.*; import p2.*; public class Application { public static void main(String[] args) {B b = new B(); D d = new D(); E e = new E(); System.out.println(\"Hello Java Test-3 \"); }}" 7 | }, 8 | { 9 | "filename": "Root/p1/B.java", 10 | "content": "package p1; public class B { public B() {C c = new C(); System.out.println(\"Hello B\"); }}" 11 | }, 12 | { 13 | "filename": "Root/p1/C.java", 14 | "content": "package p1; public class C { public C() {System.out.println(\"Hello C\"); }}" 15 | }, 16 | { 17 | "filename": "Root/p2/D.java", 18 | "content": "package p2; public class D { public D() {System.out.println(\"Hello D\"); }}" 19 | }, 20 | { 21 | "filename": "Root/p2/E.java", 22 | "content": "package p2; public class E { public E() {System.out.println(\"Hello E\"); }}" 23 | }, 24 | { 25 | "filename": "Root/codeboard.json", 26 | "content": "{\n\t\"MainFileForCompilation\": \"Application.java\",\n\t\"MainClassForRunning\":\"Application\"\n}" 27 | } 28 | ], 29 | "action": "compile", 30 | "stream": false 31 | } -------------------------------------------------------------------------------- /app/components/angularTreeview/angular.treeview.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | @license Angular Treeview version 0.1.6 3 | ⓒ 2013 AHN JAE-HA http://github.com/eu81273/angular.treeview 4 | License: MIT 5 | */ 6 | 7 | (function(f){f.module("angularTreeview",[]).directive("treeModel",function($compile){return{restrict:"A",link:function(b,h,c){var a=c.treeId,g=c.treeModel,e=c.nodeLabel||"label",d=c.nodeChildren||"children",e='
  • {{node.'+e+'}}
    2 | 3 |
    4 |
    5 | 6 |
    7 |
    8 |
    9 |

    Sign in

    10 |
    11 |
    12 |
    13 |
    14 | 15 | 16 |
    17 |
    18 | 19 | 20 |
    21 |

    {{formData.error}}

    22 | 23 |
    24 |
    25 |
    26 |
    27 | 28 |
    29 | 30 |
    31 |
    32 |
    33 | Forgot your password? Reset your password here. 34 |
    35 |
    36 |
    37 | -------------------------------------------------------------------------------- /app/components/angularTreeview/css/angular.treeview.css: -------------------------------------------------------------------------------- 1 | div[data-angular-treeview] { 2 | /* prevent user selection */ 3 | -moz-user-select: -moz-none; 4 | -khtml-user-select: none; 5 | -webkit-user-select: none; 6 | -ms-user-select: none; 7 | user-select: none; 8 | 9 | /* default */ 10 | font-family: Tahoma; 11 | font-size:13px; 12 | color: #555; 13 | text-decoration: none; 14 | } 15 | 16 | div[data-tree-model] ul { 17 | margin: 0; 18 | padding: 0; 19 | list-style: none; 20 | border: none; 21 | } 22 | 23 | div[data-tree-model] li { 24 | position: relative; 25 | padding: 0 0 0 20px; 26 | line-height: 20px; 27 | } 28 | 29 | div[data-tree-model] li .expanded { 30 | padding: 1px 10px; 31 | background-image: url("../img/folder.png"); 32 | background-repeat: no-repeat; 33 | } 34 | 35 | div[data-tree-model] li .collapsed { 36 | padding: 1px 10px; 37 | background-image: url("../img/folder-closed.png"); 38 | background-repeat: no-repeat; 39 | } 40 | 41 | div[data-tree-model] li .normal { 42 | padding: 1px 10px; 43 | background-image: url("../img/file.png"); 44 | background-repeat: no-repeat; 45 | } 46 | 47 | div [data-tree-model] li .node-text { 48 | white-space: nowrap; 49 | } 50 | 51 | div[data-tree-model] li i, div[data-tree-model] li span { 52 | cursor: default; 53 | } 54 | 55 | div[data-tree-model] li .selected { 56 | background-color: #aaddff; 57 | font-weight: bold; 58 | padding: 1px 5px; 59 | } 60 | -------------------------------------------------------------------------------- /app/scripts/controllers/signinCtrl.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('codeboardApp') 4 | .controller('SigninCtrl', ['$scope', '$rootScope', '$http', '$location', '$routeParams', 5 | function ($scope, $rootScope, $http, $location, $routeParams) { 6 | 7 | $scope.formData = {}; 8 | $scope.signinFailed = false; 9 | 10 | // function to submit the form 11 | $scope.signin = function(formData) { 12 | 13 | $scope.submitted = true; 14 | 15 | var payload = { 16 | username: formData.username, 17 | password: formData.password 18 | } 19 | 20 | $http.post('/api/session', payload) 21 | .success(function(data, status, header, config) { 22 | 23 | if($routeParams.redirect) { 24 | // there's redirect information, so we redirect to that rather then the user's profile page 25 | $location.url($routeParams.redirect); 26 | } 27 | else { 28 | // redirect to the user page 29 | $location.path('/users/' + data.username); 30 | } 31 | }) 32 | .error(function(data, status) { 33 | 34 | $scope.signinFailed = true; 35 | 36 | if(status === 401) { 37 | $scope.formData.error = 'Invalid username, email or password.'; 38 | } 39 | else { 40 | $scope.formData.error = 'Unknown error. Please try again.'; 41 | } 42 | }); 43 | }; 44 | 45 | }]); 46 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "codeboard", 3 | "description": "Codeboard, the web-based IDE for the classroom. Core of the codeboard.io project.", 4 | "version": "0.1.0", 5 | "authors": [ 6 | {"name": "H.-Christian Estler", "email": "christian@codeboard.io"}, 7 | {"name": "Martin Nordio", "email": "martin@codeboard.io"} 8 | ], 9 | "homepage": "https://codeboard.io", 10 | "repository": { 11 | "type": "git", 12 | "url": "git://github.com/codeboardio/codeboard.git" 13 | }, 14 | "dependencies": { 15 | "angular": "1.3.18", 16 | "json3": "3.2.6", 17 | "es5-shim": "2.1.0", 18 | "jquery": "1.11.0", 19 | "angular-bootstrap": "0.14.3", 20 | "ng-file-upload-shim": "1.6.1", 21 | "ng-file-upload": "1.6.1", 22 | "bootstrap": "3.3.2", 23 | "angular-resource": "1.3.18", 24 | "angular-cookies": "1.3.18", 25 | "angular-sanitize": "1.3.18", 26 | "angular-route": "1.3.18", 27 | "angular-animate": "1.3.18", 28 | "ace-builds": "1.2.0", 29 | "angular-ui-ace": "0.2.3", 30 | "jsSHA": "1.5.0", 31 | "angular-ui-select": "0.11.2", 32 | "selectize": "0.8.5", 33 | "ng-grid": "2.0.13", 34 | "kendo-ui": "2015.1.318+Official", 35 | "Chart.js": "1.0.2", 36 | "angular-chart.js": "0.8.4", 37 | "angular-websocket": "1.0.13", 38 | "angular-scroll-glue": "2.0.6" 39 | }, 40 | "devDependencies": { 41 | "angular-mocks": "1.3.18", 42 | "angular-scenario": "1.3.18" 43 | }, 44 | "license": "MIT" 45 | } 46 | -------------------------------------------------------------------------------- /app/views/partials/supportLtiDebug.html: -------------------------------------------------------------------------------- 1 |
    2 | 3 |
    4 |
    5 | 6 |
    7 | 8 |

    Lti Debug

    9 | 10 |
    Use the following settings
    11 |

    12 | Url: https://codeboard.io/support/lti/debug 13 |

    14 |

    15 | key: coboLtiDebug
    16 | secret: secret 17 |

    18 | 19 | 20 |

    Initial request

    21 | 22 |
    Lti Request body
    23 | 24 | 25 | 26 |

    Data from request that's used for sending back the grade

    27 | 28 |

    SourcedId: {{data.sourcedId}}

    29 |

    Outcome service url: {{data.outcomeServiceUrl}}

    30 | 31 | 32 |

    The grade to send back (decimal value between 0 and 1)

    33 | 34 | 35 | 36 |

    Tool Consumer replies to sending grade with

    37 |
    Status: {{data.responseStatusCode}}
    38 | 39 |
    Header:
    40 | 41 | 42 |
    Body:
    43 | 44 | 45 |
    46 | 47 |
    48 | 49 |
    50 | -------------------------------------------------------------------------------- /app/scripts/controllers/supportCtrl.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('codeboardApp') 4 | .controller('SupportCtrl', ['$scope', '$rootScope', '$http', '$routeParams', '$location', 5 | function ($scope, $rootScope, $http, $routeParams, $location) { 6 | 7 | $scope.data = { 8 | reqBody: '', 9 | outcomeServiceUrl: '', 10 | sourcedId: '', 11 | 12 | responseHeader: '', 13 | responseBody: '', 14 | responseStatusCode: 0 15 | } 16 | 17 | 18 | var init = function() { 19 | 20 | var _reqBody = JSON.parse(decodeURIComponent($routeParams.reqBody)); 21 | 22 | var foo = '' 23 | for(var x in _reqBody) { 24 | foo = foo + x + '=' + _reqBody[x] + '\n'; 25 | } 26 | 27 | 28 | $scope.data.reqBody = foo; 29 | 30 | $scope.data.outcomeServiceUrl = _reqBody.lis_outcome_service_url; 31 | $scope.data.sourcedId = _reqBody.lis_result_sourcedid; 32 | 33 | }(); 34 | 35 | $scope.sendGrade = function(gradeValue) { 36 | 37 | var payload = { 38 | grade: gradeValue, 39 | lis_outcome_service_url: $scope.data.outcomeServiceUrl, 40 | lis_result_sourcedid: $scope.data.sourcedId 41 | } 42 | 43 | $http.put('/support/lti/debug/outcome', payload) 44 | .success(function(data, status, header, config) { 45 | 46 | $scope.data.responseStatusCode = data.statusCode; 47 | $scope.data.responseHeader = data.headers; 48 | $scope.data.responseBody = data.body; 49 | 50 | 51 | }) 52 | .error(function(data, status, header, config) { 53 | 54 | }); 55 | }; 56 | 57 | 58 | }]); 59 | -------------------------------------------------------------------------------- /test/server/init/0_initDB.js: -------------------------------------------------------------------------------- 1 | var env = process.env.NODE_ENV = process.env.NODE_ENV || 'test'; 2 | 3 | var //app = require('../../../server.js'), 4 | request = require('supertest'), 5 | express = require('express'), 6 | should = require('should'), 7 | bodyParser = require('body-parser'); 8 | 9 | var db = require('../../../lib/models'); 10 | 11 | describe('Test Server: Init the DB', function () { 12 | 13 | this.timeout(5000); 14 | 15 | it('DB: create empty data BD with dummy data', function (done) { 16 | // Disable the foreign key constraints before trying to sync the models. 17 | // Otherwise, we're likely to violate a constraint while dropping a table. 18 | db.sequelize.query('SET FOREIGN_KEY_CHECKS = 0') 19 | .spread(function (res, meta) { 20 | return db.sequelize.sync({force: true}); 21 | }) 22 | .then(function () { 23 | return db.sequelize.query('SET FOREIGN_KEY_CHECKS = 1'); 24 | }) 25 | .spread(function (res, meta) { 26 | if (false) { 27 | console.log('Error in initDB:'); 28 | console.log(err); 29 | throw err[0] 30 | } else { 31 | 32 | // write some test data in the db 33 | var templateProjects = require('../../../lib/config/dbTemplateProjects.js'); 34 | var dbDummyData = require('./dbDummyData.js'); 35 | 36 | templateProjects.addAllTemplateProjects() 37 | .then(function() { 38 | return dbDummyData.createDbDummyData(); 39 | }) 40 | .then(function() { 41 | done(); 42 | }); 43 | } 44 | }); 45 | }); 46 | 47 | }); 48 | -------------------------------------------------------------------------------- /lib/services/toolSrv.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This service calls the Kali server and gets the 3 | * result of testing a project 4 | * 5 | * @param projectId 6 | * @param files 7 | * @param options 8 | */ 9 | var config = require('../config/config.js'), 10 | http = require('http'), 11 | Promise = require('bluebird'), 12 | request = Promise.promisifyAll(require('request')); // use bluebird promises for requests 13 | 14 | 15 | /** 16 | * Invokes the Eiffel compilation and returns a promise 17 | * @param data {object} contains the files and a property "language" 18 | * @returns {*|Promise} a bluebird promise 19 | */ 20 | var tool = function tool (data) { 21 | 22 | 23 | // the Tara domain name 24 | var url = config.tara.url + ':' + config.tara.port + '/test'; 25 | 26 | // we define the kali payload according to the specs: https://github.com/DOSE-ETH/kali/wiki 27 | var payload = { 28 | action: 'test', 29 | language: data.language, 30 | files: data.files, 31 | testFiles: [] 32 | }; 33 | 34 | // return the promise that resolves when the compilation finishes and the server replies 35 | return request.postAsync({url: url, json: true, body: payload}) 36 | .spread(function (res, body) { 37 | 38 | if (res.statusCode >= 400) { 39 | // create an error object 40 | var err = { 41 | statusCode: res.statusCode, 42 | msg: res.body.msg 43 | }; 44 | 45 | // reject the promise with the error object 46 | return Promise.reject(err); 47 | } 48 | else { 49 | return body; 50 | } 51 | }); 52 | }; 53 | 54 | 55 | module.exports = { 56 | tool: tool 57 | }; 58 | -------------------------------------------------------------------------------- /lib/config/passport.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by haches on 7/8/14. 3 | * 4 | * Defines the strategy of passport.js 5 | * 6 | * Provides serialization & de-serialization functions for sessions. 7 | */ 8 | 9 | 10 | 'use strict'; 11 | 12 | var db = require('../models'), 13 | Sequelize = require('sequelize'), 14 | passport = require('passport'), 15 | LocalStrategy = require('passport-local').Strategy, 16 | util = require('../util.js'); 17 | 18 | /** 19 | * Passport configuration 20 | */ 21 | passport.serializeUser(function(user, done) { 22 | done(null, user); 23 | }); 24 | 25 | passport.deserializeUser(function(user, done) { 26 | done(null, user); 27 | }); 28 | 29 | // add other strategies for more authentication flexibility 30 | passport.use(new LocalStrategy({ 31 | usernameField: 'username', // these are optional & only need be used in case 'username' and 'password' are names used in the request 32 | passwordField: 'password' // this is the virtual field on the model 33 | }, 34 | function(username, password, done) { 35 | 36 | db.User.find({attributes: ['id', 'username', 'email', 'password', 'salt'], where: Sequelize.or({username: username}, {email: username})}) 37 | .then(function(user) { 38 | if(user === null) 39 | return done(null, false, {message: 'User is not registered.'}); 40 | 41 | if(!util.verifyPassword(password, user.password, user.salt)) 42 | return done(null, false, {message: 'Incorrect password'}); 43 | 44 | return done(null, {id: user.id, username: user.username, email: user.email}); // we serialize the username, id and email 45 | }) 46 | .error(function(err) { 47 | return done(err); 48 | }); 49 | } 50 | )); 51 | 52 | module.exports = passport; -------------------------------------------------------------------------------- /db_templates/Java-JUnit/Root/test/FinderTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Tests for class Finder. 3 | * 4 | * All tests in the folder "test" are executed 5 | * when the "Test" action is invoked. 6 | * 7 | */ 8 | 9 | import static org.junit.Assert.*; 10 | import org.junit.Test; 11 | 12 | 13 | public class FinderTest { 14 | 15 | @Test 16 | public final void testFindMaximumElement1() { 17 | 18 | // we define some test input and what result we would expect 19 | int[] testInput = new int[] { 1, 2, 3, 4, 5 }; 20 | int expectedResult = 5; 21 | 22 | // create a Finder object and call the findMaximumElement function 23 | // with test input 24 | Finder myFinder = new Finder(); 25 | int actualResult = myFinder.findMaximumElement(testInput); 26 | 27 | // the actualResult value should be the same as the expectedResult value 28 | assertTrue("Test input with ascending order", 29 | actualResult == expectedResult); 30 | } 31 | 32 | @Test 33 | public final void testFindMaximumElement2() { 34 | 35 | int[] testInput = new int[] { 117, 56, 38, 11, 0 }; 36 | int expectedResult = 117; 37 | 38 | Finder myFinder = new Finder(); 39 | int actualResult = myFinder.findMaximumElement(testInput); 40 | 41 | assertTrue("Test input with descending order", 42 | actualResult == expectedResult); 43 | } 44 | 45 | @Test 46 | public final void testFindMaximumElement3() { 47 | 48 | int[] testInput = new int[] { 42, 11, 38, 75, 14 }; 49 | int expectedResult = 75; 50 | 51 | Finder myFinder = new Finder(); 52 | int actualResult = myFinder.findMaximumElement(testInput); 53 | 54 | assertTrue("Test input with random order", 55 | actualResult == expectedResult); 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /lib/models/user.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by haches on 7/7/14. 3 | * 4 | * The ORM model of a user. 5 | */ 6 | 7 | var util = require('./../util.js'); 8 | 9 | 10 | module.exports = function(sequelize, DataTypes) { 11 | 12 | var User = sequelize.define( 13 | 'User', 14 | { 15 | username: { 16 | type: DataTypes.STRING, 17 | unique: true 18 | }, 19 | email: { 20 | type: DataTypes.STRING, 21 | unique: true 22 | }, 23 | emailPublic: DataTypes.STRING, 24 | name: DataTypes.STRING, 25 | password: { 26 | type: DataTypes.STRING(2048), 27 | set: function(aPassword) { 28 | 29 | // Note: we can't use Sequelize validation here because we use a custom "setter" function. With those, 30 | // validation doesn't work. Instead, we need to validate the length of password when handling the request. 31 | // See also: https://github.com/sequelize/sequelize/issues/2367 32 | 33 | // sets the password when a new user instance is created; we don't store the password directly but hash it. 34 | this.salt = util.getSalt(); // create a new salt 35 | this.setDataValue('password', util.getEncryptedPassword(aPassword, this.salt)); // generate a hashed password together with salt 36 | } 37 | }, 38 | salt: DataTypes.STRING(1024), 39 | url: DataTypes.STRING, 40 | location: DataTypes.STRING, 41 | institution: DataTypes.STRING, 42 | imageUrl: DataTypes.STRING 43 | }, 44 | { 45 | classMethods: { 46 | associate: function(models) { 47 | User.belongsToMany(models.Project, {as: 'ownerSet', through: 'ProjectsOwners'}); 48 | User.belongsToMany(models.Project, {as: 'userSet', through: 'ProjectsUsers'}); 49 | } 50 | } 51 | } 52 | ); 53 | 54 | return User; 55 | }; 56 | -------------------------------------------------------------------------------- /app/scripts/controllers/userProjectsCtrl.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('codeboardApp') 4 | .controller('UserProjectsCtrl', ['$scope', '$rootScope', '$routeParams', '$http', '$location', '$route', 'UserSrv', 5 | function ($scope, $rootScope, $routeParams, $http, $location, $route, UserSrv) { 6 | 7 | /* Object that stores all the data of the user */ 8 | $scope.user = {}; 9 | 10 | /* Object that stores info about all the projects own by the user */ 11 | $scope.ownerSet = {}; 12 | 13 | /* Object that stores info about all the projects used by the user */ 14 | $scope.userSet = {}; 15 | 16 | /* Parameter that is true if the user is watching her own page, otherwise false; use to display buttons */ 17 | $scope.currentUserIsSelf = false; 18 | 19 | /** 20 | * Function runs when the controller is loaded the first time. 21 | * Gets the user and user's project data from the server. 22 | */ 23 | $scope.init = function() { 24 | 25 | $http.get('/api/users/' + $routeParams.username + '/projects') 26 | .success(function(data) { 27 | 28 | $scope.user = { 29 | // id 30 | username: data.username, 31 | name: data.name, 32 | email: data.emailPublic, 33 | url: data.url, 34 | location: data.location, 35 | institution: data.institution, 36 | imageUrl: data.imageUrl 37 | } 38 | 39 | $scope.ownerSet = data.ownerSet; 40 | 41 | $scope.userSet= data.userSet; 42 | 43 | $scope.currentUserIsSelf = (UserSrv.isAuthenticated() && data.username === UserSrv.getUsername()); 44 | }) 45 | .error(function(err) { 46 | // there was an error, most likely we didn't find the user, so we redirect to the 404 47 | $location.path('/404').replace(); 48 | }); 49 | }(); 50 | 51 | }]); 52 | -------------------------------------------------------------------------------- /app/scripts/controllers/projectSubmissionsCtrl.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Created by haches on 18.07.2014. 5 | * 6 | * Controller for administrating an object. 7 | * We assume that this controller is only loaded 8 | * if the current user is an owner of the project. 9 | * Nevertheless, the server must validate the 10 | * users authorization again before storing any changes. 11 | */ 12 | 13 | angular.module('codeboardApp') 14 | .controller('ProjectSubmissionsCtrl', ['$scope', '$log', '$routeParams', '$http', 15 | function ($scope, $log, $routeParams, $http) { 16 | 17 | 18 | $scope.usernameFilter = undefined; 19 | $scope.projectId = $routeParams.projectId; 20 | 21 | $scope.submissionData = []; 22 | 23 | 24 | 25 | /** 26 | * Function is run when the controller loads to fetch the stats for compilation and runs of the project. 27 | */ 28 | var init = function() { 29 | 30 | var _projectId = $routeParams.projectId; 31 | 32 | $http.get('/api/projects/' + _projectId + '/submissions') 33 | .success(function(data, status, headers, config) { 34 | 35 | $scope.submissionData = data; 36 | }) 37 | .error(function(data, status, headers, config) { 38 | 39 | $log.debug('Can not get the submissions'); 40 | 41 | }); 42 | }(); 43 | 44 | 45 | /** 46 | * Function to return the sum of all values stored in an array under "propertyname". 47 | * @param inputArray the array over which to iterate 48 | * @param propertyName the name of the property of each array element that should be summed 49 | * @return {number} the total sum 50 | */ 51 | var getTotal = function(inputArray, propertyName) { 52 | var result = 0; 53 | 54 | for(var i = 0; i < inputArray.length; i++) { 55 | result += inputArray[i][propertyName]; 56 | } 57 | 58 | return result; 59 | } 60 | 61 | }]); 62 | -------------------------------------------------------------------------------- /app/scripts/controllers/projectUserProjectsCtrl.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Created by haches on 18.07.2014. 5 | * 6 | * Controller for administrating an object. 7 | * We assume that this controller is only loaded 8 | * if the current user is an owner of the project. 9 | * Nevertheless, the server must validate the 10 | * users authorization again before storing any changes. 11 | */ 12 | 13 | angular.module('codeboardApp') 14 | .controller('ProjectUserProjectsCtrl', ['$scope', '$log', '$routeParams', '$http', 15 | function ($scope, $log, $routeParams, $http) { 16 | 17 | 18 | $scope.usernameFilter = undefined; 19 | $scope.projectId = $routeParams.projectId; 20 | 21 | $scope.userProjects = []; 22 | 23 | 24 | 25 | /** 26 | * Function is run when the controller loads to fetch the stats for compilation and runs of the project. 27 | */ 28 | var init = function() { 29 | 30 | var _projectId = $routeParams.projectId; 31 | 32 | $http.get('/api/projects/' + _projectId + '/userprojects') 33 | .success(function(data, status, headers, config) { 34 | 35 | $scope.userProjects = data; 36 | }) 37 | .error(function(data, status, headers, config) { 38 | 39 | $log.debug('Can not get the userprojects'); 40 | 41 | }); 42 | }(); 43 | 44 | 45 | /** 46 | * Function to return the sum of all values stored in an array under "propertyname". 47 | * @param inputArray the array over which to iterate 48 | * @param propertyName the name of the property of each array element that should be summed 49 | * @return {number} the total sum 50 | */ 51 | var getTotal = function(inputArray, propertyName) { 52 | var result = 0; 53 | 54 | for(var i = 0; i < inputArray.length; i++) { 55 | result += inputArray[i][propertyName]; 56 | } 57 | 58 | return result; 59 | } 60 | 61 | }]); 62 | -------------------------------------------------------------------------------- /lib/util.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by hce on 7/10/14. 3 | * 4 | * A collection of utility functionality that is 5 | * used by for the models. 6 | * 7 | * We put this in this separate file because there's 8 | * no simple way of adding arbitrary functions to the 9 | * sequelizejs models. (At least we current way we use 10 | * module.export in the model files). 11 | * 12 | */ 13 | 14 | var crypto = require('crypto'); 15 | 16 | 17 | var getSalt = function() { 18 | return crypto.randomBytes(16).toString('base64'); 19 | }; 20 | 21 | /** 22 | * Returns a hashed password based on the inputs. 23 | * @param aPassword the password in clear text 24 | * @param aSalt a salt that's used during the hashing 25 | * @return the hashed password 26 | * @private 27 | */ 28 | var getEncryptedPassword = function(aPassword, aSalt) { 29 | if (!aPassword || !aSalt) return ''; 30 | return crypto.pbkdf2Sync(aPassword, aSalt, 10000, 64).toString('base64'); 31 | }; 32 | 33 | /** 34 | * Verifies a given password against it's hashed version. 35 | * @param aPasswordClearText the password in clear text 36 | * @param aHashedPassword the password hash 37 | * @param aSalt the salt that was used to hash the password 38 | * @return {boolean} true if the password is matched to the hashed password, otherwise false 39 | * @private 40 | */ 41 | var verifyPassword = function(aPasswordClearText, aHashedPassword, aSalt) { 42 | return getEncryptedPassword(aPasswordClearText, aSalt) === aHashedPassword; 43 | }; 44 | 45 | var getRandomPassword = function() { 46 | 47 | // create a random number, put it base 36, cut off the last 8 characters 48 | // source: http://stackoverflow.com/questions/9719570/generate-random-password-string-with-requirements-in-javascript 49 | return Math.random().toString(36).slice(-8); 50 | }; 51 | 52 | exports.getSalt = getSalt; 53 | exports.getEncryptedPassword = getEncryptedPassword; 54 | exports.verifyPassword = verifyPassword; 55 | exports.getRandomPassword = getRandomPassword; 56 | -------------------------------------------------------------------------------- /app/components/ngGrid/ngGridHeight.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by hce on 10/6/14. 3 | */ 4 | 5 | 6 | function ngGridFlexibleHeightPlugin (opts) { 7 | var self = this; 8 | self.grid = null; 9 | self.scope = null; 10 | self.init = function (scope, grid, services) { 11 | self.domUtilityService = services.DomUtilityService; 12 | self.grid = grid; 13 | self.scope = scope; 14 | var recalcHeightForData = function () { setTimeout(innerRecalcForData, 1); }; 15 | var innerRecalcForData = function () { 16 | var gridId = self.grid.gridId; 17 | var footerPanelSel = '.' + gridId + ' .ngFooterPanel'; 18 | var extraHeight = self.grid.$topPanel.height() + $(footerPanelSel).height(); 19 | var naturalHeight = self.grid.$canvas.height() + 1; 20 | if (opts != null) { 21 | if (opts.minHeight != null && (naturalHeight + extraHeight) < opts.minHeight) { 22 | naturalHeight = opts.minHeight - extraHeight - 2; 23 | } 24 | if (opts.maxHeight != null && (naturalHeight + extraHeight) > opts.maxHeight) { 25 | naturalHeight = opts.maxHeight; 26 | } 27 | } 28 | 29 | var newViewportHeight = naturalHeight + 3; 30 | if (!self.scope.baseViewportHeight || self.scope.baseViewportHeight !== newViewportHeight) { 31 | self.grid.$viewport.css('height', newViewportHeight + 'px'); 32 | self.grid.$root.css('height', (newViewportHeight + extraHeight) + 'px'); 33 | self.scope.baseViewportHeight = newViewportHeight; 34 | self.domUtilityService.RebuildGrid(self.scope, self.grid); 35 | } 36 | }; 37 | self.scope.catHashKeys = function () { 38 | var hash = '', 39 | idx; 40 | for (idx in self.scope.renderedRows) { 41 | hash += self.scope.renderedRows[idx].$$hashKey; 42 | } 43 | return hash; 44 | }; 45 | self.scope.$watch('catHashKeys()', innerRecalcForData); 46 | self.scope.$watch(self.grid.config.data, recalcHeightForData); 47 | }; 48 | } 49 | -------------------------------------------------------------------------------- /app/scripts/services/uploadService.js: -------------------------------------------------------------------------------- 1 | //angular.module('codeboardApp').factory('uploadService', function($resource) { 2 | 3 | //} 4 | var uploadService = angular.module('uploadService', ['ngResource', 'angularFileUpload']); 5 | 6 | var MyCtrl = [ '$scope', '$upload', function($scope, $upload) { 7 | $scope.onSendFiles = function($files) { 8 | 9 | //$files: an array of files selected, each file has name, size, and type. 10 | for (var i = 0; i < $files.length; i++) { 11 | var currentFile = $files[i]; 12 | //alert("Loading file! "+currentFile.name); 13 | var sentFile = { 14 | url: '/uploadProfilePicture/'+$scope.userId, //upload.php script, node.js route, or servlet url 15 | data: {user: $scope.userId}, 16 | file: currentFile 17 | 18 | // file: $files, //upload multiple files, this feature only works in HTML5 FromData browsers 19 | /* set file formData name for 'Content-Desposition' header. Default: 'file' */ 20 | //fileFormDataName: myFile, //OR for HTML5 multiple upload only a list: ['name1', 'name2', ...] 21 | /* customize how data is added to formData. See #40#issuecomment-28612000 for example */ 22 | //formDataAppender: function(formData, key, val){} //#40#issuecomment-28612000 23 | }; 24 | $scope.upload = $upload.upload(sentFile).progress(function(evt) { 25 | //alert("Loading!"); 26 | // alert('percent: ' + parseInt(100.0 * evt.loaded / evt.total)); 27 | }).success(function(data, status, headers, config) { 28 | // file is uploaded successfully 29 | alert(data.reply); 30 | //console.log(data); 31 | }); 32 | //.error(...) 33 | //.then(success, error, progress); 34 | } 35 | // $scope.upload = $upload.upload({...}) alternative way of uploading, sends the the file content directly with the same content-type of the file. Could be used to upload files to CouchDB, imgur, etc... for HTML5 FileReader browsers. 36 | }; 37 | }]; 38 | //} 39 | //); 40 | -------------------------------------------------------------------------------- /lib/models/submission.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by hce on 9/8/14. 3 | * 4 | * The database model for submissions. 5 | * It stores all the files that belong to the submission. 6 | * It stores the user who submitted if the user is known. 7 | */ 8 | 9 | 10 | module.exports = function(sequelize, DataTypes) { 11 | var Submission = sequelize.define( 12 | 'Submission', 13 | { 14 | // does the project produce test results 15 | hasResult: DataTypes.BOOLEAN, 16 | 17 | // the test result (if any) 18 | testResult: { 19 | type: DataTypes.DECIMAL(7, 4), // store 7 places, with 4 to the right of the decimal (precision) 20 | defaultValue: -1 21 | }, 22 | 23 | // number of passed tests 24 | numTestsPassed: { 25 | type: DataTypes.INTEGER, 26 | defaultValue: -1 27 | }, 28 | 29 | // number of failed tests 30 | numTestsFailed: { 31 | type: DataTypes.INTEGER, 32 | defaultValue: -1 33 | }, 34 | 35 | // stores all the data from the user's project (as a big JSON array) 36 | userFilesDump: 'MEDIUMTEXT', // Note: this 'hack' gets us the right data type for MYSQL; might not work with other DB systems 37 | 38 | // stores the files that were hidden by the time of the submission 39 | hiddenFilesDump: 'MEDIUMTEXT'// Note: this 'hack' gets us the right data type for MYSQL; might not work with other DB systems 40 | }, 41 | { 42 | classMethods: { 43 | associate: function(models) { 44 | Submission.belongsTo(models.Project, {as: 'project', onDelete: 'CASCADE'}); 45 | Submission.belongsTo(models.User, {as: 'user', constraints: false}); // Note: disable the default constraints of belongsTo because a submission might be by an anonymous user 46 | Submission.belongsTo(models.LtiSession, {as: 'ltiSession', constraints: false}); // Note: disable the default constraints of belongsTo because a submission might not have an associated LTI session 47 | } 48 | } 49 | } 50 | 51 | 52 | ); 53 | 54 | return Submission; 55 | }; 56 | -------------------------------------------------------------------------------- /test/server/06_testPartials.js: -------------------------------------------------------------------------------- 1 | var env = process.env.NODE_ENV = process.env.NODE_ENV || 'test'; 2 | 3 | var app = require('../../server.js'), 4 | request = require('supertest'), 5 | express = require('express'), 6 | should = require('should'), 7 | bodyParser = require('body-parser'), 8 | expect = require('chai').expect; 9 | 10 | app.use(bodyParser()); 11 | 12 | var cookie,cookie2; 13 | var req = request(app); 14 | var eiffelId, cId, javaId, haskellId; 15 | var eiffelProjectSettings; 16 | 17 | describe('Test Server: Partials', function() { 18 | before(function(done) { 19 | req 20 | .post('/api/session') 21 | .send({username: 'hce', password: '1234'}) 22 | .expect('Content-Type', /json/ ) 23 | .expect(200) 24 | .end(function(error, reply) { 25 | //console.log(reply); 26 | cookie = reply.headers['set-cookie'].pop().split(';')[0]; //.headers['set-cookie']; 27 | req 28 | .post('/api/session') 29 | .send({username: 'martin', password: '1234'}) 30 | .expect('Content-Type', /json/ ) 31 | .expect(200) 32 | .end(function(error, reply) { 33 | //console.log(reply); 34 | cookie2 = reply.headers['set-cookie'].pop().split(';')[0]; //.headers['set-cookie']; 35 | done(); 36 | }); 37 | }); 38 | }); 39 | 40 | it('Main: main page', function(done) { 41 | req 42 | .get('/') 43 | .set('cookie', cookie) 44 | //.expect('Content-Type', /json/) 45 | //.expect(201) 46 | .end(function(error, reply) { 47 | if(error) return done(error); 48 | console.log(reply.body); 49 | done() 50 | }); 51 | }); 52 | 53 | // TODO: working here 54 | it('Partials: main page', function(done) { 55 | req 56 | .get('/partials/main') 57 | .set('cookie', cookie) 58 | //.expect('Content-Type', /json/) 59 | //.expect(201) 60 | .end(function(error, reply) { 61 | if(error) return done(error); 62 | console.log(reply.body); 63 | done() 64 | }); 65 | }); 66 | 67 | 68 | 69 | 70 | }); 71 | -------------------------------------------------------------------------------- /app/views/partials/projectUserProjects.html: -------------------------------------------------------------------------------- 1 |
    2 | 3 |
    4 |
    5 |
    6 |

    Versions saved by users for project {{projectId}}

    7 |
    8 |
    9 | 10 |
    11 |
    12 | 13 |
    14 |
    15 | 16 |
    17 |
    18 |
    19 |

    No user versions found.

    20 |

    It looks like no users have saved versions of this project.

    21 |

    It looks like user '{{usernameFilter}}' has not saved a version of this project.

    22 |
    23 |
    24 |
    25 | 26 |
    27 |
    28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 |
    UserLast save
    {{elem.username}}{{elem.updatedAt | date: 'medium'}}Open in IDE
    40 |
    41 |
    42 | 43 |
    44 | -------------------------------------------------------------------------------- /db_templates/Java-JUnit/Root/test_submission/SubTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Tests used to check a submission. 3 | * 4 | * All tests in the "test_submission" folder are used for 5 | * checking a submission and are executed when the 6 | * "Submission" action is invoked. 7 | * 8 | */ 9 | 10 | import static org.junit.Assert.*; 11 | import org.junit.Before; 12 | import org.junit.Rule; 13 | import org.junit.Test; 14 | import org.junit.rules.ExpectedException; 15 | 16 | 17 | public class SubTest { 18 | 19 | /** the finder instance */ 20 | Finder finder = new Finder(); 21 | 22 | /** 23 | * Before running any test, we create a Finder instance which is then used 24 | * by all the tests. 25 | */ 26 | @Before 27 | public void setUp() { 28 | finder = new Finder(); 29 | } 30 | 31 | /** 32 | * Defines a rule that allows in-test specification of expected exception 33 | * types and messages. 34 | */ 35 | @Rule 36 | public ExpectedException exception = ExpectedException.none(); 37 | 38 | /** 39 | * Testing the Finder with non-negative numbers. 40 | */ 41 | @Test 42 | public final void testNonNegativeValues() { 43 | int actualResult = finder.findMaximumElement( 44 | new int[] { 115, 54, 3, 0, 76, 665 }); 45 | assertTrue("Testing non-negative inputs", actualResult == 665); 46 | } 47 | 48 | /** 49 | * Testing the Finder with negative numbers. 50 | */ 51 | @Test 52 | public final void testNegativeValues() { 53 | 54 | int actualResult = finder.findMaximumElement( 55 | new int[] { -11, -55, -1, -12 }); 56 | assertTrue("Testing negative inputs", actualResult == -1); 57 | } 58 | 59 | /** 60 | * Testing the Finder with an empty array as input. We expect the 61 | * findMaximumElement method to throw an error. 62 | */ 63 | @Test 64 | public final void testEmptyArray() { 65 | exception.expect(Error.class); 66 | exception.expectMessage("Array is empty."); 67 | int actualResult = finder.findMaximumElement(new int[] {}); 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /app/scripts/controllers/projectNewCtrl.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Created by haches on 18.07.2014. 5 | * 6 | * Controller for administrating an object. 7 | * We assume that this controller is only loaded 8 | * if the current user is an owner of the project. 9 | * Nevertheless, the server must validate the 10 | * users authorization again before storing any changes. 11 | */ 12 | 13 | angular.module('codeboardApp') 14 | .controller('ProjectNewCtrl', ['$scope', '$http', '$routeParams', '$location', '$route', '$timeout', 15 | function ($scope, $http, $routeParams, $location, $route, $timeout) { 16 | 17 | // Object that holds the properties of a project and binds to the form 18 | $scope.data = { 19 | language: 'Java-JUnit' 20 | }; 21 | 22 | // Object's values are used to show success or failure message after saving data to server 23 | $scope.server = { 24 | saveSuccess: false, 25 | saveFailure: false 26 | } 27 | 28 | 29 | $scope.save = function(form) { 30 | 31 | var projectId = $routeParams.projectId; 32 | 33 | if(form.$valid) { 34 | 35 | var payload = { 36 | projectname: $scope.data.projectname, 37 | description: $scope.data.description, 38 | language: $scope.data.language, 39 | isPrivate: $scope.data.isPrivate 40 | } 41 | 42 | // hide user messages (in case they are displayed from a previous saving attempt) 43 | $scope.server.saveSuccess = false; 44 | $scope.server.saveFailure = false; 45 | 46 | $http 47 | .post('/api/projects/', payload) 48 | .success(function(data, status, headers, config) { 49 | 50 | // show the success message 51 | $scope.server.saveSuccess = true; 52 | 53 | // redirect to the summary page of the project 54 | $location.path( "/projects/" + data.id + '/summary'); 55 | }) 56 | .error(function(data, status, headers, config) { 57 | // show the error message and remove it after 4 seconds 58 | $scope.server.saveFailure = true; 59 | }); 60 | } 61 | } 62 | 63 | }]); 64 | -------------------------------------------------------------------------------- /lib/models/project.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by haches on 7/7/14. 3 | * 4 | * The ORM model of project. 5 | */ 6 | 7 | 8 | module.exports = function(sequelize, DataTypes) { 9 | var Project = sequelize.define( 10 | 'Project', 11 | { 12 | // the name of the project 13 | projectname: DataTypes.STRING, 14 | 15 | // the programming language of the project 16 | language: DataTypes.STRING, 17 | 18 | // the description of the project 19 | description: DataTypes.TEXT, 20 | 21 | // the last id used in the project (for managing files) 22 | lastUId: DataTypes.INTEGER, 23 | 24 | // the code that user can use to gain access to a project 25 | code: {type: DataTypes.STRING, defaultValue: '42'}, 26 | 27 | // is the project a private project 28 | isPrivate: {type: DataTypes.BOOLEAN, defaultValue: false}, 29 | 30 | // does the project allow users to submit their solutions, e.g. through a submit-button 31 | isSubmissionAllowed: {type: DataTypes.BOOLEAN, defaultValue: false}, 32 | 33 | // is the availability of the project restricted to a certain time frame 34 | isTimeRestricted: {type: DataTypes.BOOLEAN, defaultValue: false}, 35 | 36 | // the start time when a timely restricted project becomes available 37 | timeRestricitonStart: {type: DataTypes.DATE, defaultValue: DataTypes.NOW}, 38 | 39 | // the end time after which a timely restricted project is available 40 | timeRestrictionEnd: {type: DataTypes.DATE, defaultValue: DataTypes.NOW}, 41 | 42 | // is the access to the project via LTI allowed 43 | isLtiAllowed: {type: DataTypes.BOOLEAN, defaultValue: false}, 44 | 45 | // the lti key 46 | ltiKey: {type: DataTypes.STRING, defaultValue: ''}, 47 | 48 | // the lti secret 49 | ltiSecret: {type: DataTypes.STRING, defaultValue: ''} 50 | }, 51 | { 52 | classMethods: { 53 | associate: function(models) { 54 | Project.belongsToMany(models.User, {as: 'ownerSet', through: 'ProjectsOwners'}); 55 | Project.belongsToMany(models.User, {as: 'userSet', through: 'ProjectsUsers'}); 56 | Project.hasMany(models.File, {as: 'fileSet'}); 57 | } 58 | } 59 | } 60 | ); 61 | 62 | return Project; 63 | }; 64 | 65 | 66 | -------------------------------------------------------------------------------- /app/views/partials/passwordReset.html: -------------------------------------------------------------------------------- 1 |
    2 | 3 |
    4 |
    5 | 6 |
    7 |
    8 |
    9 |

    Password reset

    10 |
    11 |
    12 |

    13 | Enter the email associated with your Codeboard account.
    14 | We'll send you a new password to that address. 15 |

    16 |
    17 |
    19 | 20 | 21 |

    22 | This email is not associated with a Codeboard account. 23 |

    24 |
    25 |

    {{formData.error}}

    26 | 27 |
    28 | 29 | 32 | 35 |
    36 |
    37 |
    38 |
    39 | 40 |
    41 |
    42 |
    43 | Not registered yet? Sign up here.
    44 | Need help? Contact support@codeboard.io 45 |
    46 |
    47 | 48 |
    49 | -------------------------------------------------------------------------------- /app/styles/main.css: -------------------------------------------------------------------------------- 1 | /* Space out content a bit */ 2 | 3 | html, body { 4 | height: 100%; 5 | } 6 | 7 | body { 8 | padding-bottom: 21px; 9 | } 10 | 11 | /* Everything but the jumbotron gets side spacing for mobile first views */ 12 | .header, 13 | .marketing, 14 | .footer { 15 | padding-left: 15px; 16 | padding-right: 15px; 17 | } 18 | 19 | /* Custom page header */ 20 | .header { 21 | border-bottom: 1px solid #e5e5e5; 22 | } 23 | /* Make the masthead heading the same height as the navigation */ 24 | .header h3 { 25 | margin-top: 0; 26 | margin-bottom: 0; 27 | line-height: 40px; 28 | padding-bottom: 19px; 29 | } 30 | 31 | /* Custom page footer */ 32 | .footer { 33 | padding-top: 19px; 34 | color: #777; 35 | border-top: 1px solid #e5e5e5; 36 | } 37 | 38 | /* Customize container */ 39 | @media (min-width: 768px) { 40 | .container { 41 | max-width: 1050px; 42 | } 43 | } 44 | .container-narrow > hr { 45 | margin: 30px 0; 46 | } 47 | 48 | /* Main marketing message and sign up button */ 49 | .jumbotron { 50 | text-align: center; 51 | border-bottom: 1px solid #e5e5e5; 52 | } 53 | .jumbotron .btn { 54 | font-size: 21px; 55 | padding: 14px 24px; 56 | } 57 | 58 | /* Supporting marketing content */ 59 | .marketing { 60 | margin: 40px 0; 61 | } 62 | .marketing p + h4 { 63 | margin-top: 28px; 64 | } 65 | 66 | /* Responsive: Portrait tablets and up */ 67 | @media screen and (min-width: 768px) { 68 | /* Remove the padding we set earlier */ 69 | .header, 70 | .marketing, 71 | .footer { 72 | padding-left: 0; 73 | padding-right: 0; 74 | } 75 | /* Space out the masthead */ 76 | .header { 77 | margin-bottom: 30px; 78 | } 79 | /* Remove the bottom border on the jumbotron for visual effect */ 80 | .jumbotron { 81 | border-bottom: 0; 82 | } 83 | } 84 | 85 | .blackboard { 86 | color: white; 87 | background-color: #262D2D; 88 | } 89 | 90 | .main-container-space { 91 | padding: 8em 0em; 92 | } 93 | 94 | .main-screenshot { 95 | border: 1px solid #d3d3d3; 96 | border-radius: 4px; 97 | } 98 | 99 | .main-lti-logo { 100 | margin-top: 40px; 101 | margin-bottom: 40px; 102 | height: 45px; 103 | } 104 | 105 | .main-mooc { 106 | border: 1px solid #000000; 107 | border-radius: 4px; 108 | } 109 | 110 | .main-feature-list li { 111 | padding-bottom: 10px; 112 | } 113 | 114 | .main-learn-more { 115 | font-size: 14px; 116 | } 117 | -------------------------------------------------------------------------------- /app/views/partials/main.html: -------------------------------------------------------------------------------- 1 |
    2 | 3 |
    4 |
    5 |
    6 |
    7 | 8 | 9 |
    10 |
    11 |
    12 | Responsive image 13 |
    14 |
    15 | 16 |
    17 |
    18 |
      19 |
    • A web-based IDE to teach programming in the classroom.
    • 20 |
    • Easily create and share exercises with students.
    • 21 |
    • Analyze and inspect students' submissions with a single click.
    • 22 |
    23 |
    24 |
    25 |
    26 | 27 |
    28 | No account? Sign up here. 29 | 30 |
    31 | 32 |
    33 | 35 |
    36 |
    37 | 39 |
    40 | 41 |
    42 |

    Invalid username, email or password.

    43 | 44 |
    45 | 46 |
    47 |
    48 |
    49 |
    50 |
    51 | 52 | 53 |
    54 |
    55 | 56 |
    57 |

    58 | This is an Open-Codeboard installation. Learn more at open.codeboard.io 59 |

    60 |
    61 |
    62 |
    63 | 64 |
    65 | -------------------------------------------------------------------------------- /lib/config/env/all.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'); 4 | 5 | // determine the path of the folder where server.js lives (go backwards from lib/config/env) 6 | var rootPath = path.normalize(__dirname + '/../../..'); 7 | 8 | module.exports = { 9 | 10 | // the port on which Codeboard runs 11 | port: process.env.PORT || 3000, 12 | 13 | // path to the root folder 14 | root: rootPath, 15 | 16 | // where to store users' profile pictures 17 | userProfileImagePath: 'images/users/profiles', 18 | 19 | // where the default user profile pictures are located 20 | userProfileDefaultImagePath:'images/users/defaults', 21 | 22 | // settings of the MYSQL database 23 | db: { 24 | port: '3306', 25 | host: '127.0.0.1', 26 | username: 'mysqlUser', 27 | password: 'mysqlPassword' 28 | }, 29 | 30 | // settings of the Mongo database 31 | mongo: { 32 | options: { 33 | db: { 34 | safe: true 35 | }, 36 | user: 'mongoUser', 37 | pass: 'mongoPassword' 38 | } 39 | }, 40 | 41 | codeboard: { 42 | // protocol and hostname that's presented when announcing a WebSocket address (e.g. to connect to a container) 43 | wsHostname: 'ws://localhost:9000' 44 | }, 45 | 46 | // settings of the Mantra service (for compiling and running programs) 47 | mantra: { 48 | // Mantra is our service 49 | ip: '127.0.0.1', 50 | url: 'http://127.0.0.1', 51 | port: 9090, 52 | cookieName: 'CoboMantraId' 53 | }, 54 | 55 | // settings of the Kali service (for unit-testing programs) 56 | kali: { 57 | // Kali is our testing service 58 | url: 'http://127.0.0.1', 59 | port: 9091 60 | }, 61 | 62 | // Tara is our tool service; might be the same physical server as Mantra 63 | tara: { 64 | url: 'http://127.0.0.1', 65 | port: 9090 66 | }, 67 | 68 | // configuration for nodemailer as used in mailSrv (to send welcome email, email password reset etc.) 69 | // list of pre-configured services: https://github.com/andris9/nodemailer-wellknown#supported-services 70 | email: { 71 | service: '', // e.g. Gandi 72 | user: '', // e.g. myUser 73 | password: '', // e.g. s3%$#@#%34zJL53 74 | 75 | // the email address from which emails are send (welcome email, password reset email) 76 | // this address will show as the sender of the email 77 | defaultEmail: 'Open-Codeboard Info ' 78 | }, 79 | 80 | // configuration for session data 81 | sessionSettings: { 82 | name: 'codeboard', 83 | secret: 'evmdoaafxeosuqsifcpnbmdhvxeam', 84 | 85 | // we persisted sessions using Mongo database (except when testing) 86 | mongoStoreDbName: 'codeboardSession' 87 | } 88 | }; 89 | -------------------------------------------------------------------------------- /app/scripts/controllers/passwordResetCtrl.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Created by haches on May 06 2015. 5 | * Angular controller for the password reset page. 6 | */ 7 | 8 | angular.module('codeboardApp') 9 | .controller('PasswordResetCtrl', ['$scope', '$rootScope', '$http', '$location', '$routeParams', 10 | function ($scope, $rootScope, $http, $location, $routeParams) { 11 | 12 | // the form's data 13 | $scope.formData = {}; 14 | 15 | // initially the from is not submitted 16 | $scope.submitted = false; 17 | // when the form is under submission, we want to deactivate the submit button and not send another request 18 | $scope.isUnderSubmission = false; 19 | 20 | // object that's used to dynamically show/hide error and success information in the HTML template 21 | $scope.server = { 22 | resetSuccess: false, // the password reset was successful 23 | errorUnknownFailure: false, // there was an unkown error while trying to reset the password 24 | errorEmailUnknown: false // the email address is not registered with Codeboard 25 | }; 26 | 27 | 28 | /** 29 | * Sends the password reset request to the server. 30 | * @param {Object} formData the data from the form (has only the single property 'email') 31 | */ 32 | $scope.resetPassword = function (formData) { 33 | 34 | // the user submitted the form, we're processing it 35 | $scope.submitted = true; 36 | // disable the submit button 37 | $scope.isUnderSubmission = true; 38 | 39 | // reset any error or success status that might be active from a previous submission 40 | $scope.server.resetSuccess = false; 41 | $scope.server.errorEmailUnknown = false; 42 | $scope.server.errorUnknownFailure = false; 43 | 44 | var payload = { 45 | email: formData.email 46 | } 47 | 48 | 49 | $http.put('/api/passwordreset', payload) 50 | .success(function (data, status, header, config) { 51 | 52 | // show the confirmation that a new password was send via email 53 | $scope.server.resetSuccess = true; 54 | // enable the submit button 55 | $scope.isUnderSubmission = false; 56 | 57 | }) 58 | .error(function (data, status) { 59 | 60 | // enable the submit button 61 | $scope.isUnderSubmission = false; 62 | 63 | if (status === 403) { 64 | $scope.server.errorEmailUnknown = true; 65 | } 66 | else { 67 | $scope.server.errorUnknownFailure = true; 68 | } 69 | }); 70 | }; 71 | 72 | }]); 73 | -------------------------------------------------------------------------------- /app/scripts/services/websocketSrv.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Service that provides WebSocket functionality, specifically designed 3 | * to work well with the Mantra backend service. 4 | * 5 | * Calling the service returns the object with functions to connect, close 6 | * or send data over the WebSocket. 7 | * 8 | * Created by hce on 28/08/15. 9 | */ 10 | 11 | 12 | angular.module('codeboardApp') 13 | .factory('WebsocketSrv', ['$websocket', '$log', function ($websocket, $log) { 14 | 15 | // reference to the WS instance 16 | var ws = null; 17 | 18 | 19 | /** 20 | * Function to connects to a websocket. 21 | * @param {string} aWeSocketUrl the Url of the websocket 22 | * @param {string} aStartUrl 23 | * @param onWSDataCallback 24 | * @param onWSCloseCallback 25 | */ 26 | var connect = function(aWeSocketUrl, onWSOpenCallback, onWSDataCallback, onWSCloseCallback) { 27 | 28 | // create the WS connection 29 | ws = $websocket(aWeSocketUrl); 30 | 31 | // when the WS is open, we call the start Url 32 | ws.onOpen(function() { 33 | onWSOpenCallback(); 34 | }); 35 | 36 | // when a new message is received over the WS 37 | ws.onMessage(function(msg) { 38 | onWSDataCallback(msg.data); 39 | }); 40 | 41 | // when the WS is closed 42 | ws.onClose(function() { 43 | $log.debug('websocketSrvjs.onClose: the websocket connection was closed!'); 44 | onWSCloseCallback(); 45 | }); 46 | 47 | // when there's an error 48 | ws.onError(function() { 49 | $log.debug('websocketSrvjs.onError: websocket error'); 50 | }); 51 | 52 | }; 53 | 54 | /** 55 | * Closes the websocket. 56 | * @param {boolean} [aForceClose=false] force the closing 57 | */ 58 | var close = function(aForceClose) { 59 | var lForceClose = aForceClose || false; 60 | ws.close(lForceClose); 61 | }; 62 | 63 | /** 64 | * Send data over the WebSocket. 65 | * @param {string} aInputData - the data to send 66 | */ 67 | var sendData = function(aInputData) { 68 | if (ws && ws.readyState === 1) { 69 | // readyState 1 is: connection is open and ready to communicate 70 | // (see: https://developer.mozilla.org/en-US/docs/Web/API/WebSocket#Ready_state_constants) 71 | $log.debug('WebsocketSrvjs.sendData: sending data ' + aInputData); 72 | ws.send(aInputData); 73 | } 74 | else { 75 | $log.debug('WebsocketSrvjs.sendData: not sending data; WS not initialized or readyState not 1'); 76 | } 77 | } 78 | 79 | // the object we return 80 | return { 81 | connect: connect, 82 | close: close, 83 | sendData: sendData 84 | }; 85 | 86 | }]); 87 | -------------------------------------------------------------------------------- /app/views/partials/projectNew.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
    4 |
    5 | 6 |
    7 |
    8 |
    9 |

    New project

    10 |
    11 |
    12 | 13 |
    14 |
    15 | 16 | 17 |
    18 |
    19 | 20 | 21 |
    22 |
    23 | 24 | 34 | 35 |
    36 |
    37 | 38 |
    39 | 42 | 43 |
    44 |
    45 | 46 | 47 | Cancel 48 |
    49 | 50 | 53 | 56 | 57 |
    58 |
    59 |
    60 |
    61 |
    62 | -------------------------------------------------------------------------------- /app/views/partials/projectSubmissions.html: -------------------------------------------------------------------------------- 1 |
    2 | 3 |
    4 |
    5 |
    6 |

    Submissions for project {{projectId}}

    7 |
    8 |
    9 | 10 |
    11 |
    12 | 13 |
    14 |
    15 | 16 |
    17 |
    18 |
    19 |

    No submissions found.

    20 |

    It looks like this project has no submissions.

    21 |

    It looks like user '{{usernameFilter}}' has no submissions.

    22 |
    23 |
    24 |
    25 | 26 |
    27 |
    28 |
      29 |
    • 30 |

      31 | {{elem.username}} 32 | {{elem.username}} 33 | ({{elem.submissions.length}}) 34 |

      35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 |
      CreatedResultTests passedTests failedLTI
      {{sub.createdAt | date: 'medium'}}{{sub.testResult === -1 ? '-' : sub.testResult}}{{sub.numTestsPassed === -1 ? '-' : sub.numTestsPassed}}{{sub.numTestsFailed === -1 ? '-' : sub.numTestsFailed}}{{sub.isLtiSubmission ? 'yes' : 'no'}}Open in IDE
      53 |
    • 54 |
    55 |
    56 |
    57 | 58 |
    59 | -------------------------------------------------------------------------------- /app/scripts/controllers/signupCtrl.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('codeboardApp') 4 | .controller('SignupCtrl', ['$scope', '$rootScope', '$http', '$location', 5 | function ($scope, $rootScope, $http, $location) { 6 | 7 | $scope.data = {}; 8 | $scope.serverError = { 9 | userExists: false, 10 | emailExists: false, 11 | hasErrors: false, 12 | errorMsg: '' 13 | } 14 | 15 | // will be set to true once a user tried to submit the form; use to enable the displaying of form validation errors 16 | $scope.submitted = false; 17 | 18 | // will be set to true once we've submitted and are waiting for the server to get back to us; used to prevent multiple submissions 19 | $scope.currentlySubmitting = false; 20 | 21 | // function to submit the form after all validation has occurred 22 | $scope.register = function(form) { 23 | 24 | $scope.submitted = true; 25 | 26 | // check to make sure the form is completely valid and we're not currently submitting 27 | if (form.$valid & $scope.data.password === $scope.data.passwordConfirm && $scope.currentlySubmitting == false) { 28 | 29 | $scope.currentlySubmitting = true; 30 | 31 | var payload = { 32 | username: $scope.data.username, 33 | password: $scope.data.password, 34 | email: $scope.data.email 35 | } 36 | 37 | 38 | $http 39 | .post('/api/users', payload) 40 | .success(function(data, status, header, config) { 41 | $scope.serverError.userExists = false; 42 | $scope.serverError.emailExists = false; 43 | 44 | $scope.currentlySubmitting = false; 45 | 46 | // we try to login the user immediately after the signup 47 | $http.post('/api/session', 48 | { 49 | username: $scope.data.username, 50 | password: $scope.data.password 51 | }) 52 | .success(function(data, status, header, config) { 53 | $location.path('/users/' + data.username); 54 | }); 55 | }) 56 | .error(function(data, status) { 57 | if(status === 422) { 58 | // probably failed the server side validation 59 | $scope.serverError.hasErrors = true; 60 | $scope.serverError.errorMsg = data.msg; 61 | } 62 | else if(status === 409) { 63 | // username or email might already exist 64 | if(data.error === 'UserExists') { 65 | $scope.serverError.userExists = true; 66 | } 67 | if(data.error === 'EmailExists') { 68 | $scope.serverError.emailExists = true; 69 | } 70 | } 71 | else { 72 | // some other error occurred on the server 73 | $scope.serverError.hasErrors = true; 74 | $scope.serverError.errorMsg = data.msg; 75 | } 76 | 77 | $scope.currentlySubmitting = false; 78 | }); 79 | } 80 | }; 81 | }]); 82 | -------------------------------------------------------------------------------- /app/views/partials/projectSummary.html: -------------------------------------------------------------------------------- 1 |
    2 | 3 | 4 |
    5 | 6 |
    7 |
    8 | 9 |
    10 |
    11 |
      12 |
    • 13 | 14 |

      {{prj.projectname}}

      15 | 16 |

      {{prj.description}}

      17 |
    • 18 |
    19 |
    20 |
    21 | 22 |
    23 |
    24 | 25 |

    {{prj.language}}

    26 |
    27 |
    28 | 29 |
    30 |
    31 | 32 |
    33 | 36 |
    37 |
    38 |
    39 | 40 |
    41 |
    42 | 43 |

    44 | {{owner.username}} 45 |

    46 |
    47 |
    48 | 49 |
    50 |
    51 | 52 |

    53 | https://codeboard.io/projects/{{prj.id}} 54 |

    55 |
    56 |
    57 | 58 |
    59 |
    60 | Open in IDE 61 |
    62 | 63 | 64 | 65 | 66 |
    67 |
    68 |
    69 | 70 |
    71 |
    72 | 73 |
    74 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Codeboard 2 | 3 | Codeboard is a web-based IDE to teach programming in the classroom. This is the core of the Codeboard web application. Part of the codeboard.io project. 4 | 5 | ### Requirements 6 | 7 | Codeboard requires NodeJS, MySQL, MongoDB, and graphicsmagick (for resizing user profile pictures). 8 | 9 | * Nodejs: tested with version 0.12.9 10 | * MongoDB: tested with version 2.6.4 11 | * Codeboard has been tested on an Ubuntu 14.04 system. 12 | 13 | 14 | ### Preparing the server 15 | 16 | We need to install MySQL and create a database: 17 | 18 | ``` 19 | # Update packages and sources 20 | sudo apt-get update 21 | 22 | # Install MySQL and set the the root password 23 | sudo apt-get install mysql-server 24 | 25 | # Tell MySQL to create its DB directory structure 26 | sudo mysql_install_db 27 | 28 | # Run a security script 29 | sudo mysql_secure_installation 30 | 31 | # You should now create a db user with limited privilges and a secure password. 32 | # Then create the database for codeboard using the MySQL command: CREATE SCHEMA `codeboard` ; 33 | # You might also want to create other database, e.g. for testing: CREATE SCHEMA `codeboard-test`; 34 | ``` 35 | 36 | We also need to install MongoDB. Follow the instructions [here](https://www.digitalocean.com/community/tutorials/how-to-install-mongodb-on-ubuntu-14-04). 37 | 38 | ## Installing Codeboard 39 | 40 | Clone the repository to your server 41 | ``` 42 | git clone https://github.com/codeboardio/codeboard.git 43 | ``` 44 | 45 | Change into the Codeboard folder and install all dependencies 46 | ``` 47 | cd codeboard 48 | 49 | # Install all server dependencies 50 | npm install 51 | 52 | # Make sure to have Bower installed 53 | sudo npm install -g bower 54 | 55 | # Install all client dependencies 56 | bower install 57 | ``` 58 | 59 | Codeboard uses Grunt to automate various tasks. Make sure to have the Grunt-CLI installed 60 | ``` 61 | sudo npm install -g grunt-cli 62 | ``` 63 | 64 | ## Configuring Codeboard 65 | 66 | Codeboard requires a number of settings, like database names, passwords, etc. 67 | All those configurations must be set in the following files 68 | ``` 69 | lib/config/env/all.js 70 | lib/config/env/development.js 71 | lib/config/env/production.js 72 | lib/config/env/test.js 73 | ``` 74 | 75 | ## Run and Test Codeboard 76 | 77 | Use the following command to run Codeboard (in development mode) 78 | ``` 79 | grunt serve 80 | ``` 81 | 82 | Build an optimize version for production deployment 83 | ``` 84 | # Will create a folder dist 85 | # Deploy from dist using command: NODE_ENV=production node server.js 86 | grunt build 87 | ``` 88 | 89 | Test Codeboard 90 | ``` 91 | # run client-side tests 92 | grunt test:client 93 | 94 | # run server-side tests 95 | grunt test:server 96 | ``` 97 | 98 | 99 | ### Licensing 100 | This project is available under the MIT license. See [LICENSE](https://github.com/codeboardio/mantra/blob/master/LICENSE) for the full license text. 101 | 102 | _Important_: This project may use 3rd party software which uses others licenses. If you're planning to use this project, make sure your use-case complies with all 3rd party licenses. 103 | -------------------------------------------------------------------------------- /lib/services/mailSrv.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by hce on 06/05/15. 3 | * 4 | * This service provides functionality to 5 | * send official Codeboard emails. 6 | * 7 | */ 8 | 9 | var db = require('../models'), 10 | nodemailer = require('nodemailer'), 11 | Promise = require('bluebird'), 12 | config = require('../config/config.js'); 13 | 14 | 15 | // create reusable transport object (using default SMTP transport) 16 | 17 | // promisify the transport and sendMail operations 18 | var transport = Promise.promisifyAll(nodemailer.createTransport({ 19 | service: config.email.service, 20 | auth: { 21 | user: config.email.user, 22 | pass: config.email.password 23 | } 24 | })); 25 | 26 | /** 27 | * Sends an email throught the Codeboard Email account. 28 | * @param {String} aFrom sender address of the email 29 | * @param {String} aTo receiver address of the email 30 | * @param {String} aSubject the email's subject 31 | * @param {String} aText the email's text 32 | * @return {Promise} a bluebird promise that resolves to function(error, info) 33 | */ 34 | var sendMail = function (aFrom, aTo, aSubject, aText) { 35 | return transport.sendMailAsync ({ 36 | from: aFrom, to: aTo, subject: aSubject, text: aText 37 | }); 38 | }; 39 | 40 | 41 | /** 42 | * Sends the welcome email to the given user 43 | * @param aUsername the Codeboard username (use in the welcome message) 44 | * @param aUserEmail the user's email address used in the signup 45 | */ 46 | var sendWelcomeMail = function (aUsername, aUserEmail) { 47 | 48 | // template for the welcome email 49 | var welcomeMail = { 50 | from: config.email.defaultEmail, 51 | to: aUserEmail, 52 | subject: 'Welcome to Codeboard', 53 | text: 'Welcome ' + aUsername + ',\n\n' + 54 | 'Thank you for signing up for Codeboard!\n\n' + 55 | "In case you ever forget your password, we'll use this email address to send you a new one.\n\n" + 56 | 'Happy hacking :)\n' 57 | }; 58 | 59 | // send the mail and return a promise 60 | return sendMail(welcomeMail.from, welcomeMail.to, welcomeMail.subject, welcomeMail.text); 61 | }; 62 | 63 | 64 | /** 65 | * Sends an email with a new password 66 | * @param {String} aEmail the address to where to send the new password 67 | * @param {String} aNewPassword the new password 68 | * @return {Promise} promise that resolves to nodemailer values (error, info) 69 | */ 70 | var sendResetPasswordMail = function (aEmail, aNewPassword) { 71 | 72 | // template for the reset password email 73 | var resetMail = { 74 | from: config.email.defaultEmail, 75 | to: aEmail, 76 | subject: 'Password reset for Codeboard', 77 | text: "You're receiving this email because you requested a password reset " + 78 | "for your Codeboard user account.\n\n" + 79 | 'Your new password is: ' + aNewPassword + '\n\n' + 80 | "After signing in you can change your password again (in the user profile settings).\n\n" + 81 | 'Happy hacking :)\n' 82 | }; 83 | 84 | // send the mail and return a promise 85 | return sendMail(resetMail.from, resetMail.to, resetMail.subject, resetMail.text); 86 | }; 87 | 88 | // export the service functions 89 | exports.sendMail = sendMail; 90 | exports.sendWelcomeMail = sendWelcomeMail; 91 | exports.sendResetPasswordMail = sendResetPasswordMail; 92 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "codeboard", 3 | "description": "Codeboard, the web-based IDE for the classroom. Core of the codeboard.io project.", 4 | "version": "0.1.0", 5 | "contributors": [ 6 | { 7 | "name": "H.-Christian Estler", 8 | "email": "christian@codeboard.io" 9 | }, 10 | { 11 | "name": "Martin Nordio", 12 | "email": "martin@codeboard.io" 13 | } 14 | ], 15 | "scripts": { 16 | "start": "grunt serve", 17 | "build": "grunt build", 18 | "testClient": "grunt test:client", 19 | "testServer": "grunt test:server" 20 | }, 21 | "repository": { 22 | "type": "git", 23 | "url": "git://github.com/codeboardio/codeboard.git" 24 | }, 25 | "dependencies": { 26 | "bluebird": "2.2.2", 27 | "body-parser": "1.3.0", 28 | "compression": "1.1.0", 29 | "connect-busboy": "0.0.1", 30 | "connect-mongo": "git://github.com/haches/connect-mongo", 31 | "cookie-parser": "1.3.3", 32 | "ejs": "0.8.4", 33 | "express": "4.5.1", 34 | "express-session": "1.6.4", 35 | "express-validator": "2.3.0", 36 | "gm": "1.9.0", 37 | "http-proxy": "1.11.2", 38 | "lodash": "3.3.1", 39 | "mongoose": "3.8.8", 40 | "mysql": "2.3.2", 41 | "nodemailer": "1.3.4", 42 | "oauth-signature": "1.1.3", 43 | "passport": "0.2.0", 44 | "passport-local": "0.1.6", 45 | "request": "2.40.0", 46 | "sequelize": "2.1.3" 47 | }, 48 | "devDependencies": { 49 | "chai": "3.4.1", 50 | "connect-livereload": "0.3.0", 51 | "expect.js": "0.3.1", 52 | "grunt": "0.4.5", 53 | "grunt-autoprefixer": "3.0.3", 54 | "grunt-concurrent": "2.1.0", 55 | "grunt-contrib-clean": "0.7.0", 56 | "grunt-contrib-coffee": "0.13.0", 57 | "grunt-contrib-compass": "1.0.4", 58 | "grunt-contrib-concat": "0.5.1", 59 | "grunt-contrib-copy": "0.8.2", 60 | "grunt-contrib-cssmin": "0.14.0", 61 | "grunt-contrib-htmlmin": "0.6.0", 62 | "grunt-contrib-imagemin": "1.0.0", 63 | "grunt-contrib-jshint": "0.11.3", 64 | "grunt-contrib-uglify": "0.11.0", 65 | "grunt-contrib-watch": "0.6.1", 66 | "grunt-env": "0.4.4", 67 | "grunt-express-server": "0.5.1", 68 | "grunt-google-cdn": "0.4.3", 69 | "grunt-karma": "0.12.1", 70 | "grunt-mocha-test": "0.12.7", 71 | "grunt-newer": "1.1.1", 72 | "grunt-ng-annotate": "1.0.1", 73 | "grunt-node-inspector": "0.4.1", 74 | "grunt-nodemon": "0.4.1", 75 | "grunt-open": "0.2.3", 76 | "grunt-rev": "0.1.0", 77 | "grunt-svgmin": "3.1.0", 78 | "grunt-usemin": "3.1.1", 79 | "istanbul": "0.3.2", 80 | "jshint-stylish": "0.1.3", 81 | "karma": "0.13.16", 82 | "karma-chai": "0.1.0", 83 | "karma-chrome-launcher": "0.2.2", 84 | "karma-coffee-preprocessor": "0.3.0", 85 | "karma-coverage": "0.5.3", 86 | "karma-firefox-launcher": "0.1.7", 87 | "karma-html2js-preprocessor": "0.1.0", 88 | "karma-mocha": "0.2.1", 89 | "karma-ng-html2js-preprocessor": "0.2.0", 90 | "load-grunt-tasks": "0.2.0", 91 | "mocha": "2.0.1", 92 | "open": "0.0.4", 93 | "requirejs": "2.1.10", 94 | "protractor": "1.4.0", 95 | "should": "2.1.0", 96 | "supertest": "0.8.2", 97 | "time-grunt": "0.2.1" 98 | }, 99 | "engines": { 100 | "node": ">=0.12.x" 101 | }, 102 | "license": "MIT" 103 | } 104 | -------------------------------------------------------------------------------- /lib/controllers/authenticationCtrl.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by haches on 7/10/14. 3 | * 4 | * Controller that handles the authentication, 5 | * in particualr login and logout. 6 | * 7 | */ 8 | 9 | var passport = require('passport'), 10 | db = require('../models'), 11 | logSrv = require('../services/logSrv.js'), 12 | mailSrv = require('../services/mailSrv.js'), 13 | coboUtil = require('../util.js'); 14 | 15 | 16 | 17 | var login = function(req, res, next) { 18 | passport.authenticate('local', function(err, user, info) { 19 | 20 | if (err) { 21 | return next(err); 22 | } 23 | 24 | if (!user) { 25 | logSrv.addPageLog(logSrv.events.failedSigninEvent(req)); 26 | return res.json(401, {message: 'Wrong username or password.', authenticated: false}); 27 | } 28 | 29 | req.logIn(user, function(err) { 30 | if (err) { 31 | return next(err); 32 | } 33 | logSrv.addPageLog(logSrv.events.signinEvent(req, user.username)); 34 | 35 | return res.json(200, {username: user.username, authenticated: true}); 36 | }); 37 | })(req, res, next); 38 | }; 39 | 40 | 41 | var logout = function(req, res) { 42 | logSrv.addPageLog(logSrv.events.signoutEvent(req)); 43 | req.logout(); 44 | res.send(200); 45 | }; 46 | 47 | 48 | var isAuthenticated = function(req, res) { 49 | if(req.isAuthenticated()) 50 | res.json(200, {username: req.user.username}); 51 | else 52 | res.json(401, {message: 'The user is not authenticated.'}); 53 | }; 54 | 55 | 56 | var resetPassword = function (req, res) { 57 | 58 | // first we validate the request 59 | req.checkBody('email', 'Email may not be empty.').notEmpty(); 60 | req.checkBody('email', 'Invalid email. Provide a valid email address.').isEmail(); 61 | 62 | var valErrors = req.validationErrors(); 63 | if(valErrors) { 64 | res.json(400, {msg: 'There have been validation errors. '}); 65 | } 66 | else { 67 | // no validation errors, so we'll try to update the user password 68 | var _email = req.body.email; 69 | 70 | db.User 71 | .find({ 72 | where: {email: _email}, 73 | attributes: ['id', 'username', 'email'] 74 | }) 75 | .then(function(usr) { 76 | 77 | if(usr != null) { 78 | // get a random password 79 | var _newPassword = coboUtil.getRandomPassword(); 80 | 81 | // password was correct, thus set the new password 82 | usr.password = _newPassword; 83 | usr.save() 84 | .then(function () { 85 | return mailSrv.sendResetPasswordMail(usr.email, _newPassword); 86 | }) 87 | .then(function (successValues) { 88 | // successValues is a complex object with data about the the email send 89 | // at the moment we don't do anything with it 90 | 91 | res.json(200, {msg: 'Password has been changed.'}); 92 | }) 93 | .catch(function(err) { 94 | console.log("Server.AuthCtrl - Error sending email to reset password: " + JSON.stringify(err)); 95 | res.json(500, {msg: 'Error sending email to reset password'}); 96 | }); 97 | } 98 | else { 99 | // no user with the given email found 100 | res.json(403, {msg: 'The provided email is not registered.'}); 101 | } 102 | }); 103 | } 104 | 105 | 106 | }; 107 | 108 | exports.login = login; 109 | exports.logout = logout; 110 | exports.isAuthenticated = isAuthenticated; 111 | exports.resetPassword = resetPassword; 112 | -------------------------------------------------------------------------------- /lib/services/templateSrv.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by haches on 7/25/14. 3 | * 4 | * This service provides functionality that is 5 | * needed to creating a new template project. 6 | */ 7 | 8 | var db = require('../models'), 9 | Promise = require('bluebird'); 10 | 11 | 12 | /** 13 | * Returns an array promises where each promise relates to a file that's been created for the project. 14 | * @param templateFiles the template files that are used to create new files 15 | * @param language the language of the project 16 | * @param projectname the name of the project 17 | * @returns {*} an array of promises 18 | */ 19 | var createFilesFromTemplateFiles = function(templateFiles, language, projectname) { 20 | 21 | /* the result is an array of promisses */ 22 | var result = []; 23 | 24 | var fileArray = templateFiles.dataValues.fileSet; 25 | 26 | for(var i in fileArray) { 27 | var promise = db.File.create({ 28 | filename: fileArray[i].filename, 29 | path: fileArray[i].path, 30 | uniqueId: fileArray[i].uniqueId, 31 | parentUId: fileArray[i].parentUId, 32 | isFolder: fileArray[i].isFolder, 33 | content: fileArray[i].content, 34 | isHidden: fileArray[i].isHidden 35 | }); 36 | 37 | result.push(promise); 38 | } 39 | 40 | return Promise.all(result); 41 | }; 42 | 43 | /** 44 | * Creates a new project with the given parameters. 45 | * The new project is bootstrapped using the template that was defined for the language (e.g. Eiffel). 46 | * @param projectname name of the project 47 | * @param description a project description 48 | * @param language the programming language of the project 49 | * @param isPrivate set to true if the project should be private 50 | * @param usernameOfOwner the username of the person that will be the owner of the project 51 | */ 52 | exports.createProjectFromTemplate = function(projectname, description, language, isPrivate, usernameOfOwner) { 53 | 54 | /* local variable to keep a reference to the new project that was created in the database */ 55 | var _generatedPrj = null; 56 | /* local variable to store the newly created project */ 57 | var _newPrj; 58 | 59 | // create the basic project from the user's input 60 | var tmpPrj = { 61 | projectname: projectname, 62 | language: language, 63 | description: description, 64 | isPrivate: isPrivate, 65 | lastUId: 20 // TODO: this needs to be calculated based on the number of files in the project 66 | }; 67 | 68 | 69 | return db.Project.create(tmpPrj) 70 | .then(function(newPrj) { 71 | _newPrj = newPrj; 72 | 73 | return db.TemplateProject.find( 74 | { 75 | where: {language: language}, 76 | include: [ 77 | { 78 | model: db.TemplateFile, 79 | as: 'fileSet', 80 | order: 'uniqueId ASC' 81 | } 82 | ] 83 | }); 84 | }) 85 | .then(function(templatePrj) { 86 | return createFilesFromTemplateFiles(templatePrj, language, projectname); 87 | }) 88 | .then(function(newFiles) { 89 | return _newPrj.setFileSet(newFiles); 90 | }). 91 | then(function(files) { 92 | // we don't care about the files that are returned 93 | // but we still have to set the owner 94 | 95 | return db.User.find({where: {username: usernameOfOwner}}); 96 | }) 97 | .then(function(user) { 98 | return _newPrj.setOwnerSet([user]); 99 | }) 100 | .then(function(ownerSet) { 101 | // we again don't care about the returned value here 102 | // just return the id of the newly created project 103 | return _newPrj.id; 104 | }) 105 | .error(function(err) { 106 | return -1; 107 | }); 108 | }; 109 | -------------------------------------------------------------------------------- /app/scripts/services/ideSnippetsSrv.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Martin on 27/01/15. 3 | */ 4 | 'use strict'; 5 | 6 | angular.module('codeboardApp') 7 | .service('IdeSnippetsSrv', function IdeSnippetsSrv() { 8 | // AngularJS will instantiate a singleton by calling "new" on this function 9 | 10 | 11 | /** 12 | * Returns msg object for request that a file should be displayed in the editor. 13 | * @param {number} aNodeId the unique id of the node that should be displayed 14 | * @return {{msg: string, data: {nodeId: *}}} 15 | */ 16 | this.getEiffelSnippet = function () { 17 | return [ 18 | { 19 | content: 'feature {${1:CLASS}} -- ${2:comment}', 20 | name: 'feature modifier', 21 | tabTrigger: 'feature' 22 | }, 23 | { 24 | content: 'note\n\tdescription : "Description of the class"\n\tauthor : "Name of author"\n\n' + 25 | 'class\n\t${1:CLASS_NAME}\n\ninherit\n\t${2:CLASS_INHERIT}\n\nfeature {${3:CLASS_FEATURE}} -- ${4: feature comment}\n\n\t${5:--Add your routines here}\n\nend', 26 | name: 'class', 27 | tabTrigger: 'class' 28 | }, 29 | { 30 | content: '${1:name}: ${2:type} = ${3}', 31 | name: 'const', 32 | tabTrigger: 'const' 33 | }, 34 | { 35 | content: 'inspect\n\t${1:exp}\nwhen ${2:value} then\n\t${3:-- code 1 here}\nelse\n\t${4:-- code 2 here}\nend', 36 | name: 'inspect', 37 | tabTrigger: 'inspect' 38 | }, 39 | { 40 | content: 'when ${2:value} then\n\t${3:-- code here}', 41 | name: 'when', 42 | tabTrigger: 'when' 43 | }, 44 | { 45 | content: 'from\n\t${1}\nuntil\n\t${2}\nloop\n\t${3}\nend', 46 | name: 'from loop', 47 | tabTrigger: 'from_loop' 48 | }, 49 | { 50 | content: 'across ${1:my_list} as ${2:ic} loop ${3:print(ic.item)} end', 51 | name: 'across loop', 52 | tabTrigger: 'across_loop' 53 | }, 54 | { 55 | content: 'if ${1:exp} then\n\t${2:-- code here }\nend', 56 | name: 'if', 57 | tabTrigger: 'if' 58 | }, 59 | { 60 | content: 'if ${1:exp} then\n\t${2:-- code}\nelse\n\t${3:-- code here}\nend', 61 | name: 'ifelse', 62 | tabTrigger: 'ifelse' 63 | }, 64 | { 65 | content: '${1:routine_name} (${2:i: INTEGER})\n\t\t${3:-- feature comment}\n\trequire\n\t\t${4:-- preconditions}\n\tdo\n\t\t${5:-- code here}\n\tensure\n\t\t${6:-- postconditions}\n\tend', 66 | name: 'routine', 67 | tabTrigger: 'routine' 68 | }, 69 | { 70 | content: 'check\n\t${1:assertion}\nend ', 71 | name: 'check', 72 | tabTrigger: 'check' 73 | }, 74 | { 75 | content: 'create ${1:var}.make (${2:arguments}) ', 76 | name: 'create', 77 | tabTrigger: 'create' 78 | }, 79 | { 80 | content: 'local\n\t${1:var}: ${2:type}', 81 | name: 'local', 82 | tabTrigger: 'local' 83 | }, 84 | { 85 | content: 'print("${1:message}%N")', 86 | name: 'Hint: print message', 87 | tabTrigger: 'hint_print' 88 | }, 89 | { 90 | content: 'from\n\tmy_list.start\nuntil\n\tmy_list.off\nloop\n\tprint (my_list.item)\n\tmy_list.forth\nend', 91 | name: 'Hint: from-loop over a list', 92 | tabTrigger: 'hint_from_loop_over_a_list' 93 | }, 94 | { 95 | content: 'across my_list as ic loop print (ic.item) end', 96 | name: 'Hint: across-loop over a list', 97 | tabTrigger: 'hint_across_loop_over_a_list' 98 | } 99 | ]; 100 | }; 101 | }); 102 | -------------------------------------------------------------------------------- /app/components/angularTreeview/README.md: -------------------------------------------------------------------------------- 1 | Angular Treeview 2 | ================ 3 | 4 | Pure [AngularJS](http://www.angularjs.org) based tree menu directive. 5 | 6 | [![ScreenShot](https://github.com/eu81273/angular.treeview/raw/master/img/preview.png)](http://jsfiddle.net/eu81273/8LWUc/) 7 | 8 | ## Installation 9 | 10 | Copy the script and css into your project and add a script and link tag to your page. 11 | 12 | ```html 13 | 14 | 15 | ``` 16 | 17 | Add a dependency to your application module. 18 | 19 | ```javascript 20 | angular.module('myApp', ['angularTreeview']); 21 | ``` 22 | 23 | Add a tree to your application. See [Usage](#usage). 24 | 25 | ## Usage 26 | 27 | Attributes of angular treeview are below. 28 | 29 | - angular-treeview: the treeview directive. 30 | - tree-id : each tree's unique id. 31 | - tree-model : the tree model on $scope. 32 | - node-id : each node's id. 33 | - node-label : each node's label. 34 | - node-children: each node's children. 35 | 36 | Here is a simple example. 37 | 38 | 39 | ```html 40 |
    47 |
    48 | ``` 49 | 50 | Example model: 51 | 52 | ```javascript 53 | $scope.treedata = 54 | [ 55 | { "label" : "User", "id" : "role1", "children" : [ 56 | { "label" : "subUser1", "id" : "role11", "children" : [] }, 57 | { "label" : "subUser2", "id" : "role12", "children" : [ 58 | { "label" : "subUser2-1", "id" : "role121", "children" : [ 59 | { "label" : "subUser2-1-1", "id" : "role1211", "children" : [] }, 60 | { "label" : "subUser2-1-2", "id" : "role1212", "children" : [] } 61 | ]} 62 | ]} 63 | ]}, 64 | { "label" : "Admin", "id" : "role2", "children" : [] }, 65 | { "label" : "Guest", "id" : "role3", "children" : [] } 66 | ]; 67 | ``` 68 | 69 | ## Selection 70 | 71 | If tree node is selected, then that selected tree node is saved to $scope."TREE ID".currentNode. By using $watch, the controller can recognize the tree selection. 72 | 73 | 74 | ```javascript 75 | $scope.$watch( 'abc.currentNode', function( newObj, oldObj ) { 76 | if( $scope.abc && angular.isObject($scope.abc.currentNode) ) { 77 | console.log( 'Node Selected!!' ); 78 | console.log( $scope.abc.currentNode ); 79 | } 80 | }, false); 81 | ``` 82 | 83 | ## Examples 84 | 85 | #### Basic example 86 | [![ScreenShot](https://github.com/eu81273/angular.treeview/raw/master/img/jsfiddle01.png)](http://jsfiddle.net/eu81273/8LWUc/) 87 | 88 | [jsFiddle - http://jsfiddle.net/eu81273/8LWUc/](http://jsfiddle.net/eu81273/8LWUc/) 89 | 90 | #### Multiple treeview example 91 | [![ScreenShot](https://github.com/eu81273/angular.treeview/raw/master/img/jsfiddle02.png)](http://jsfiddle.net/eu81273/b9Pnw/) 92 | 93 | [jsFiddle - http://jsfiddle.net/eu81273/b9Pnw/](http://jsfiddle.net/eu81273/b9Pnw/) 94 | 95 | ## Browser Compatibility 96 | 97 | Same with AngularJS. Safari, Chrome, Firefox, Opera, IE8, IE9 and mobile browsers (Android, Chrome Mobile, iOS Safari). 98 | 99 | ## Changelogs 100 | 101 | #### version 0.1.6 102 | - Fixed the bug that 'null' string appears before each 'div' generated. (Thanks to Iaac) 103 | 104 | #### version 0.1.5 105 | - support multiple treeview. (Thanks to Axel Pesme) 106 | 107 | #### version 0.1.4 108 | - prevented memory leaks. 109 | 110 | #### version 0.1.3 111 | - removed unnecessary codes. 112 | 113 | #### version 0.1.2 114 | - removed some jQuery dependency. (Issue #2) 115 | 116 | ## License 117 | 118 | The MIT License. 119 | 120 | Copyright ⓒ 2013 AHN JAE-HA. 121 | 122 | See [LICENSE](https://github.com/eu81273/angular.treeview/blob/master/LICENSE) 123 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration 2 | // http://karma-runner.github.io/0.10/config/configuration-file.html 3 | 4 | module.exports = function(config) { 5 | config.set({ 6 | // base path, that will be used to resolve files and exclude 7 | basePath: '', 8 | 9 | // testing framework to use (jasmine/mocha/qunit/...) 10 | frameworks: ['mocha', 'chai'], 11 | 12 | // Note: we use chai for assertions because it allows for 13 | // assertions in should.js expect.js and assert.js style. 14 | // However, all tests should use should.js style assertions 15 | 16 | // list of files / patterns to load in the browser 17 | files: [ 18 | // Karma dependencies to have Angular running and e.g. injection working 19 | 'app/bower_components/jquery/dist/jquery.js', 20 | 'app/bower_components/angular/angular.js', 21 | 'app/bower_components/angular-mocks/angular-mocks.js', 22 | 23 | // jsSHA 24 | 'app/bower_components/jsSHA/src/sha.js', 25 | 26 | /** Karma dependencies because of directives used in app.js */ 27 | 28 | 'app/bower_components/angular-cookies/angular-cookies.js', 29 | 'app/bower_components/angular-resource/angular-resource.js', 30 | 'app/bower_components/angular-sanitize/angular-sanitize.js', 31 | 'app/bower_components/angular-route/angular-route.js', 32 | 'app/bower_components/angular-animate/angular-animate.js', 33 | 34 | // ui.ace 35 | 'app/bower_components/ace-builds/src/ace.js', 36 | 'app/bower_components/angular-ui-ace/ui-ace.js', 37 | // angularTreeview 38 | 'app/components/angularTreeview/angular.treeview.js', 39 | // bootstrap 40 | 'app/bower_components/angular-bootstrap/ui-bootstrap-tpls.js', 41 | // angularFileUpload 42 | 'app/bower_components/ng-file-upload-shim/angular-file-upload-shim.js', 43 | 'app/bower_components/ng-file-upload/angular-file-upload.js', 44 | // ui.select 45 | 'app/bower_components/angular-ui-select/dist/select.js', 46 | // ngGrid 47 | 'app/bower_components/ng-grid/ng-grid-2.0.13.min.js', 48 | // kendo.directives 49 | 'app/bower_components/kendo-ui/js/kendo.core.min.js', 50 | 'app/bower_components/kendo-ui/js/kendo.ui.core.min.js', 51 | 'app/bower_components/kendo-ui/js/kendo.angular.min.js', 52 | // chart.js 53 | 'app/bower_components/Chart.js/Chart.min.js', 54 | 'app/bower_components/angular-chart.js/dist/angular-chart.js', 55 | // ngWebSocket 56 | 'app/bower_components/angular-websocket/angular-websocket.js', 57 | // luegg.directives 58 | 'app/bower_components/angular-scroll-glue/src/scrollglue.js', 59 | 60 | /** End of Karma dependencies because of directives used in app.js */ 61 | 62 | 63 | 'app/scripts/*.js', 64 | 'app/scripts/**/*.js', 65 | 'test/client/mock/**/*.js', 66 | 'test/client/spec/**/*.js' 67 | 68 | ], 69 | 70 | // list of files / patterns to exclude 71 | exclude: [], 72 | 73 | // web server port 74 | port: 9876, 75 | 76 | // level of logging 77 | // possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG 78 | logLevel: config.LOG_INFO, 79 | 80 | 81 | // outputs to the console should be printed 82 | client: { 83 | captureConsole: true, 84 | mocha: { 85 | bail: true 86 | } 87 | }, 88 | 89 | // enable / disable watching file and executing tests whenever any file changes 90 | autoWatch: false, 91 | 92 | 93 | // Start these browsers, currently available: 94 | // - Chrome 95 | // - ChromeCanary 96 | // - Firefox 97 | // - Opera 98 | // - Safari (only Mac) 99 | // - PhantomJS 100 | // - IE (only Windows) 101 | browsers: ['Chrome'], 102 | 103 | 104 | // Continuous Integration mode 105 | // if true, it capture browsers, run tests and exit 106 | singleRun: false 107 | }); 108 | }; 109 | -------------------------------------------------------------------------------- /lib/controllers/supportCtrl.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Created by hce on 2/23/15. 5 | */ 6 | 7 | 8 | var ltiSrv = require('../services/ltiSrv.js'), 9 | oauthSignature = require('oauth-signature'); 10 | 11 | 12 | var initLtiSession = function(req, res) { 13 | 14 | /** 15 | * Function to check if a request from an LTI request for a project is authorized. 16 | * @param req the request that was send by the LTI tool consumer (e.g. edX or Moodle) 17 | * @return {boolean} returns true it the oauth_signature matches with the LTI settings 18 | */ 19 | var isRequestAuthorized = function (req, ltiSecret) { 20 | 21 | // ge all the properties of the body, except for the one that's 'oauth_signature' 22 | var _parameters = {}; 23 | 24 | for (var property in req.body) { 25 | if (property !== 'oauth_signature') { 26 | _parameters[property] = req.body[property]; 27 | } 28 | } 29 | 30 | // for oauth we need the method that was used for this request 31 | var _httpMethod = req.method; 32 | 33 | 34 | // Note: usually we would get the protocol through 'req.protocol'; in production we're behind a load balancer and thus LTI TC's use https but req.protocol will be http 35 | var protocol = req.protocol; 36 | if(process.env.NODE_ENV && process.env.NODE_ENV === 'production') { 37 | protocol = 'https'; 38 | } 39 | // for oauth we need the full url that was used for this request 40 | var _url = protocol + '://' + req.get('host') + req.originalUrl; 41 | 42 | // for oauth we need the secret from the database (the lti key is part of the request already) 43 | var _consumerSecret = ltiSecret; 44 | // for oauth we need to put the tokenSecret property, even if we don't use it 45 | var _tokenSecret = ''; 46 | 47 | // generate the signature for the request 48 | var _encodedSignature = oauthSignature.generate(_httpMethod, _url, _parameters, _consumerSecret, _tokenSecret); 49 | 50 | // check if the signature of the request matches the signature we calculated 51 | // Note: we decode the percentage encoding of the the calculated signature 52 | return (req.body.oauth_signature === oauthSignature.Rfc3986.prototype.decode(_encodedSignature)); 53 | }; 54 | 55 | 56 | // check if request is authorized by knowing the key and secret 57 | if (!isRequestAuthorized(req, 'secret')) { 58 | 59 | // the caller is not an authorized LTI tool consumer 60 | Promise.reject('The project does not allow access via LTI or the provided key/secret combination is wrong.'); 61 | res.json(401, {msg: 'You are not authorized to access this page.'}); 62 | } 63 | else { 64 | var _reqBody = encodeURIComponent(JSON.stringify(req.body)); 65 | 66 | // encode the userId so we can put is a URL parameter 67 | var _userId = encodeURIComponent(req.body.user_id); 68 | 69 | // return a redirect; this will trigger a 'get' request for the project with parameters about the user and lti session 70 | var _uriParams = encodeURI('ltiUserId=' + _userId + '<iNonce=' + req.body.oauth_nonce + '&reqBody=' + _reqBody); 71 | res.redirect('/support/lti/debug?' + _uriParams); 72 | } 73 | }; 74 | 75 | 76 | var sendOutcome = function(req, res) { 77 | 78 | var _grade = req.body.grade; 79 | var _sourcedId = req.body.lis_result_sourcedid; 80 | var _url = req.body.lis_outcome_service_url; 81 | 82 | ltiSrv.sendGrade(_grade, _sourcedId, _url, 'coboLtiDebug', 'secret') 83 | .then(function(result, a, b, c) { 84 | 85 | // console.log('Grade send'); 86 | 87 | var payload = { 88 | statusCode: result[0].statusCode, 89 | headers: JSON.stringify(result[0].headers), 90 | body: JSON.stringify(result[0].body) 91 | }; 92 | 93 | res.json(200, payload); 94 | 95 | }) 96 | .catch(function(err) { 97 | res.send(500, err.message); 98 | }); 99 | 100 | }; 101 | 102 | 103 | 104 | module.exports = { 105 | initLtiSession: initLtiSession, 106 | sendOutcome: sendOutcome 107 | }; 108 | -------------------------------------------------------------------------------- /app/components/angularTreeview/angular.treeview.js: -------------------------------------------------------------------------------- 1 | /* 2 | @license Angular Treeview version 0.1.6 3 | ⓒ 2013 AHN JAE-HA http://github.com/eu81273/angular.treeview 4 | License: MIT 5 | 6 | 7 | [TREE attribute] 8 | angular-treeview: the treeview directive 9 | tree-id : each tree's unique id. 10 | tree-model : the tree model on $scope. 11 | node-id : each node's id 12 | node-label : each node's label 13 | node-children: each node's children 14 | 15 |
    22 |
    23 | */ 24 | 25 | (function ( angular ) { 26 | 'use strict'; 27 | 28 | angular.module( 'angularTreeview', [] ).directive( 'treeModel', ['$compile', function( $compile ) { 29 | return { 30 | restrict: 'A', 31 | link: function ( scope, element, attrs ) { 32 | //tree id 33 | var treeId = attrs.treeId; 34 | 35 | //tree model 36 | var treeModel = attrs.treeModel; 37 | 38 | //node id 39 | var nodeId = attrs.nodeId || 'uniqueId'; 40 | 41 | //node label 42 | var nodeLabel = attrs.nodeLabel || 'label'; 43 | 44 | //children 45 | var nodeChildren = attrs.nodeChildren || 'children'; 46 | 47 | //is folder property 48 | var isFolder = attrs.nodeIsFolder || 'isFolder'; 49 | 50 | //function to call on double click on node 51 | var nodeClick = attrs.nodeClick; 52 | 53 | //tree template 54 | var template = 55 | '
      ' + 56 | '
    • ' + 57 | '' + 58 | '' + 59 | ' ' + 60 | '{{node.' + nodeLabel + '}}' + 61 | '
      ' + 62 | '
    • ' + 63 | '
    '; 64 | 65 | 66 | //check tree id, tree model 67 | if( treeId && treeModel ) { 68 | 69 | //root node 70 | if( attrs.angularTreeview ) { 71 | 72 | //create tree object if not exists 73 | scope[treeId] = scope[treeId] || {}; 74 | 75 | 76 | //if node head clicks, 77 | scope[treeId].selectNodeHead = scope[treeId].selectNodeHead || function( selectedNode ){ 78 | 79 | //Collapse or Expand 80 | selectedNode.collapsed = !selectedNode.collapsed; 81 | }; 82 | 83 | //if node label clicks, 84 | scope[treeId].selectNodeLabel = scope[treeId].selectNodeLabel || function( selectedNode ){ 85 | 86 | //remove highlight from previous node 87 | if( scope[treeId].currentNode && scope[treeId].currentNode.selected ) { 88 | scope[treeId].currentNode.selected = undefined; 89 | } 90 | 91 | //set highlight to selected node 92 | selectedNode.selected = 'selected'; 93 | 94 | //set currentNode 95 | scope[treeId].currentNode = selectedNode; 96 | }; 97 | 98 | //HCE: if we have a root node, select it by default 99 | if(scope[treeModel][0]) { 100 | scope[treeId].selectNodeLabel(scope[treeModel][0]); 101 | } 102 | } 103 | 104 | //Rendering template. 105 | element.html('').append( $compile( template )( scope ) ); 106 | } 107 | } 108 | }; 109 | }]); 110 | })( angular ); 111 | -------------------------------------------------------------------------------- /lib/services/mockmantraserver.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Martin on 14/07/14. 3 | */ 4 | 5 | 6 | 'use strict'; 7 | 8 | var express = require('express'), 9 | path = require('path'), 10 | fs = require('fs'), 11 | bodyParser = require('body-parser'), 12 | util = require('util'); 13 | 14 | 15 | 16 | // once we have many express settings, we want to store them in the config file 17 | // Express settings 18 | //require('./lib/config/express')(app); 19 | 20 | 21 | /** 22 | * Main application file 23 | */ 24 | 25 | 26 | 27 | var app = express(); 28 | app.use(bodyParser()); 29 | 30 | /** 31 | * Mock the compilation service in Mantra 32 | */ 33 | app.post('/compile', function(req, res) { 34 | var data = req.body; 35 | var clean = true; 36 | clean = data.clean; 37 | console.log('Compile request Mock server'+clean); 38 | if (data.clean==='true') { 39 | res.send(200, 'Mocking CLEAN Compilation succeeded of project: '+data.id+' path '+data.path+' target '+data.target); 40 | } 41 | else { 42 | res.send(200, 'Mocking Compilation succeeded of project: '+data.id+' path '+data.path+' target '+data.target); 43 | } 44 | 45 | }); 46 | 47 | 48 | /** 49 | * Mock the run service in Mantra 50 | */ 51 | app.get('/run', function(req, res) { 52 | var id = req.query.id; 53 | res.send(200, 'Mocking Running project: '+id); 54 | 55 | }); 56 | 57 | /** 58 | * Mock the interface view service in Mantra 59 | */ 60 | app.get('/interfaceView', function(req, res) { 61 | var id = req.query.id; 62 | var className = req.query.class; 63 | res.send(200, 'Mocking interface view project: '+id+" class: "+className); 64 | 65 | }); 66 | 67 | /** 68 | * Mock the flat view service in Mantra 69 | */ 70 | app.get('/flatView', function(req, res) { 71 | var id = req.query.id; 72 | var className = req.query.class; 73 | res.send(200, 'Mocking Flat view project: '+id+" class: "+className); 74 | 75 | }); 76 | 77 | /** 78 | * Mock the contract view service in Mantra 79 | */ 80 | app.get('/contractView', function(req, res) { 81 | var id = req.query.id; // ID in Mantra 82 | var className = req.query.class; 83 | res.send(200, 'Mocking Contract view project: '+id+" class: "+className); 84 | 85 | }); 86 | 87 | /** 88 | * Mock the class descendants view service in Mantra 89 | */ 90 | app.get('/classDescendants', function(req, res) { 91 | var id = req.query.id; // ID in Mantra 92 | var className = req.query.class; 93 | res.send(200, 'Mocking Class Descendants in project: '+id+" class: "+className); 94 | 95 | }); 96 | 97 | /** 98 | * Mock the class Ancestors view service in Mantra 99 | */ 100 | app.get('/classAncestors', function(req, res) { 101 | var id = req.query.id; // ID in Mantra 102 | var className = req.query.class; 103 | res.send(200, 'Mocking Class Ancestors in project: '+id+" class: "+className); 104 | 105 | }); 106 | 107 | /** 108 | * Mock the class Clients view service in Mantra 109 | */ 110 | app.get('/classClients', function(req, res) { 111 | var id = req.query.id; // ID in Mantra 112 | var className = req.query.class; 113 | res.send(200, 'Mocking Class Clients in project: '+id+" class: "+className); 114 | 115 | }); 116 | 117 | /** 118 | * Mock the class Suppliers view service in Mantra 119 | */ 120 | app.get('/classSuppliers', function(req, res) { 121 | var id = req.query.id; // ID in Mantra 122 | var className = req.query.class; 123 | res.send(200, 'Mocking Class Suppliers in project: '+id+" class: "+className); 124 | 125 | }); 126 | 127 | /** 128 | * Mock the class Suppliers view service in Mantra 129 | */ 130 | app.get('/featureCallers', function(req, res) { 131 | var id = req.query.id; // ID in Mantra 132 | var className = req.query.class; 133 | var featureName = req.query.feature; 134 | res.send(200, 'Mocking Class feature callers in project: '+id+" class: "+className+" feature "+featureName); 135 | 136 | }); 137 | 138 | /** 139 | * Mock the class Suppliers view service in Mantra 140 | */ 141 | app.get('/commandLine', function(req, res) { 142 | var id = req.query.id; // ID in Mantra 143 | var commandLine = req.query.command_line; 144 | var featureName = req.query.feature; 145 | res.send(200, 'Mocking Command line compiler, ID: '+id+" arguments: "+commandLine); 146 | 147 | }); 148 | 149 | 150 | app.listen(7778, function () { 151 | console.log('Mocking Mantra Express server listening on port'); 152 | }); -------------------------------------------------------------------------------- /app/styles/ide.css: -------------------------------------------------------------------------------- 1 | 2 | .ideHeader { 3 | width: 100%; 4 | /* height: 54px; /* set the header to the same height as the navbar */ 5 | /*border: 1px solid #a9a9a9;*/ 6 | } 7 | 8 | #ideTreeViewProjectName { 9 | /* height: inherit; */ 10 | /*border-top: 1px solid #a9a9a9;*/ 11 | /*border-left: 1px solid #a9a9a9;*/ 12 | /*border-right: 1px solid #a9a9a9;*/ 13 | border-bottom: 1px solid #9f9f9f; 14 | /* width: 219px; /* must be the same as the tree-view element */ 15 | padding-top: 10px; 16 | padding-left: 5px; 17 | color: #777777; 18 | font-size: 16px; 19 | /* float: left; */ 20 | height: 29px; 21 | background-color: #e7e7e7; 22 | overflow: hidden; 23 | white-space: nowrap; 24 | } 25 | 26 | #ideTabArea { 27 | overflow-y: auto; /* if we have too many tabs, a scroll bar appears */ 28 | padding-left: 2px; /* the first tab has 2 pixels space compared to where the editor starts */ 29 | height: 38px; 30 | /* border-bottom: 1px solid #a9a9a9; */ 31 | margin-top: 2px; 32 | } 33 | 34 | .dropdown { 35 | /* want a pointer for all the menus */ 36 | /* we don't get it by default because we don't provide a href in the element */ 37 | cursor: pointer !important; 38 | } 39 | 40 | .ideFooter { 41 | position: absolute; 42 | height: 204px; 43 | width: 100%; 44 | bottom: 0; 45 | background-color: #e7e7e7; 46 | } 47 | 48 | .ideOutput { 49 | overflow: auto; 50 | color: #555555; 51 | background-color: #ffffff; 52 | white-space: pre; 53 | padding: 10px; 54 | position: absolute; 55 | top: 3px; 56 | bottom: 25px; 57 | left: 3px; 58 | right: 3px; 59 | } 60 | 61 | .ideOutputText { 62 | font-family: monospace; 63 | font-size: 12px; 64 | line-height: 1.42857143; 65 | } 66 | 67 | .ideOutputBorder { 68 | border: 1px solid #9f9f9f; 69 | border-radius: 3px; 70 | } 71 | 72 | .ideFooterStatusBar { 73 | height: 18px; 74 | padding-left: 5px; 75 | padding-right: 5px; 76 | padding-top: 1px; 77 | border-top: 1px solid #e7e7e7; 78 | font-size: 11px; 79 | color: #777; 80 | overflow: hidden; 81 | background-color: #f5f5f5; 82 | } 83 | 84 | .ideTree { 85 | /*position: absolute; */ 86 | /* width: 220px; */ 87 | height: 100%; 88 | overflow: auto; 89 | } 90 | 91 | .ideEditorArea { 92 | /* padding-left: 220px; */ 93 | /* height:100%; */ 94 | overflow: auto; 95 | } 96 | 97 | .ideEditor { 98 | border-top: 1px solid #9f9f9f; 99 | } 100 | 101 | #ideAceNotVisible { 102 | background-color: #e7e7e7; 103 | /* height: 100%; */ 104 | } 105 | 106 | #ideMsgNoFilesOpen { 107 | text-align: center; 108 | padding-top: 100px; 109 | color: #a9a9a9; 110 | } 111 | 112 | #ideMsgNotSignedIn { 113 | max-width: 300px; 114 | text-align: center; 115 | margin: 0 auto; 116 | margin-top: 25px; 117 | } 118 | 119 | .ideSplitterOverflowVisible { 120 | overflow: visible !important; 121 | } 122 | 123 | .ideSplitterFullHeight { 124 | height: 100%; 125 | } 126 | 127 | .ideTabs { 128 | /* margin-top: 2px;*/ 129 | margin-bottom: 0; 130 | padding-left: 0px; 131 | /* background-color: #e8e8e8; */ 132 | } 133 | 134 | .ideTabs li { 135 | list-style-type: none; 136 | border: 1px solid #d3d3d3; 137 | border-bottom: none; 138 | border-radius: 4px 4px 0 0; 139 | padding: 10px 15px; 140 | background-color: #fff; 141 | cursor: pointer; 142 | color: #333; 143 | opacity: .65; 144 | } 145 | 146 | .ideTabActive { 147 | opacity: 1 !important; 148 | border-color: #9f9f9f !important; 149 | } 150 | 151 | .ideTabs img { 152 | margin: 0 0 0 4px; 153 | } 154 | 155 | #ideNavBar { 156 | border-radius: 0; 157 | margin-bottom: 0; 158 | background-color: #f5f5f5; 159 | } 160 | 161 | .navbar-brand { 162 | padding-left: 15px; 163 | padding-top: 5px; 164 | } 165 | 166 | .ace_gutter { 167 | /* overwrite the ace gutter bg-color to match the bootstrap gray */ 168 | background-color: #e7e7e7 !important; 169 | } 170 | 171 | #ace_editor { 172 | /* border-top: 1px solid darkgray; */ 173 | /* height: 100%; */ 174 | width: 100%; 175 | /*padding-bottom: 40px; /* padding for the tab bar */ 176 | position: absolute; 177 | top: 39px; 178 | bottom: 0px; 179 | } 180 | 181 | #ideRightPartOfMiddlePart { 182 | background-color: #e7e7e7; 183 | } 184 | 185 | /* Make sure the kendo-splitter is not visible in the treeview where it splits the project-name and the LibraryCtrl */ 186 | #ideTreeviewPartOfMiddlePart .k-splitbar { 187 | background-color: #ffffff; 188 | } 189 | --------------------------------------------------------------------------------