signup and login working
arnaucode arnaucode@gmail.com
Thu, 01 Feb 2018 13:14:51 +0100
33 files changed,
1040 insertions(+),
0 deletions(-)
jump to
A
README.md
@@ -0,0 +1,18 @@
+# decentralized-blogging-platform + +Decentralized blogging platform, using IPFS + + + +### Instructions + +- Need to add: +``` +ipfs config --json API.HTTPHeaders.Access-Control-Allow-Origin '["*"]' +``` +in order to allow access to IPFS from the app. + +- Start the IPFS daemon +``` +ipfs daemon +```
A
RESTfunctions.go
@@ -0,0 +1,96 @@
+package main + +import ( + "encoding/json" + "fmt" + "net/http" + + "gopkg.in/mgo.v2/bson" +) + +type User struct { + Id bson.ObjectId `json:"id" bson:"_id,omitempty"` + Username string `json:"username"` + Email string `json:"email"` + Password string `json:"password"` + Token string `json:"token"` +} + +func Index(w http.ResponseWriter, r *http.Request) { + fmt.Fprintln(w, "clientApp") +} + +func Signup(w http.ResponseWriter, r *http.Request) { + decoder := json.NewDecoder(r.Body) + var user User + err := decoder.Decode(&user) + if err != nil { + panic(err) + } + defer r.Body.Close() + + fmt.Print("user signup: ") + fmt.Println(user.Username) + + //save the new project to mongodb + rUser := User{} + err = userCollection.Find(bson.M{"email": user.Email}).One(&rUser) + if err != nil { + //user not exists + err = userCollection.Insert(user) + err = userCollection.Find(bson.M{"email": user.Email}).One(&user) + } else { + //user exists + http.Error(w, "user already registered", http.StatusConflict) + return + } + + fmt.Println(user.Username) + jResp, err := json.Marshal(user) + if err != nil { + panic(err) + } + fmt.Fprintln(w, string(jResp)) +} + +func Login(w http.ResponseWriter, r *http.Request) { + + decoder := json.NewDecoder(r.Body) + var user User + err := decoder.Decode(&user) + if err != nil { + panic(err) + } + defer r.Body.Close() + //TODO check if the user password exists in the database + + fmt.Print("user login: ") + fmt.Println(user) + + //save the new project to mongodb + rUser := User{} + err = userCollection.Find(bson.M{"email": user.Email}).One(&rUser) + if err != nil { + http.Error(w, "error login, email not foun", http.StatusConflict) + return + } + //user exists, check password + if user.Password != rUser.Password { + http.Error(w, "error login, password not match", http.StatusConflict) + return + } + + token, err := newToken() + check(err) + rUser.Token = token + + //update with the token + err = userCollection.Update(bson.M{"_id": rUser.Id}, rUser) + check(err) + + jResp, err := json.Marshal(rUser) + if err != nil { + panic(err) + } + fmt.Fprintln(w, string(jResp)) +}
A
config.json
@@ -0,0 +1,8 @@
+{ + "apiport": "3000", + "webport": "8081", + "mongodb": { + "ip": "127.0.0.1:27017", + "database": "decentralized-blogging-platform" + } +}
A
errors.go
@@ -0,0 +1,15 @@
+package main + +import ( + "log" + "runtime" +) + +func check(err error) { + if err != nil { + _, fn, line, _ := runtime.Caller(1) + log.Println(line) + log.Println(fn) + log.Println(err) + } +}
A
hash.go
@@ -0,0 +1,12 @@
+package main + +import ( + "crypto/sha256" + "encoding/base64" +) + +func hash(s string) string { + h := sha256.New() + h.Write([]byte(s)) + return base64.URLEncoding.EncodeToString(h.Sum(nil)) +}
A
log.go
@@ -0,0 +1,19 @@
+package main + +import ( + "io" + "log" + "os" + "time" +) + +func savelog() { + timeS := time.Now().String() + _ = os.Mkdir("logs", os.ModePerm) + logFile, err := os.OpenFile("logs/log-"+timeS+".log", os.O_CREATE|os.O_APPEND|os.O_RDWR, 0666) + if err != nil { + panic(err) + } + mw := io.MultiWriter(os.Stdout, logFile) + log.SetOutput(mw) +}
A
main.go
@@ -0,0 +1,51 @@
+package main + +import ( + "fmt" + "log" + "net/http" + + "github.com/fatih/color" + "github.com/gorilla/handlers" + mgo "gopkg.in/mgo.v2" +) + +const keysDir = "keys" +const keysize = 2048 +const hashize = 1536 + +var userCollection *mgo.Collection + +func main() { + color.Blue("Starting ipfs-ai-models-market") + + readConfig("config.json") + fmt.Println(config) + + initializeToken() + + //mongodb + session, err := getSession() + check(err) + userCollection = getCollection(session, "users") + + //run thw webserver + go GUI() + + //run API + log.Println("api server running") + log.Print("port: ") + log.Println(config.APIPort) + router := NewRouter() + headersOk := handlers.AllowedHeaders([]string{"X-Requested-With", "Access-Control-Allow-Origin"}) + originsOk := handlers.AllowedOrigins([]string{"*"}) + methodsOk := handlers.AllowedMethods([]string{"GET", "HEAD", "POST", "PUT", "OPTIONS"}) + log.Fatal(http.ListenAndServe(":"+config.APIPort, handlers.CORS(originsOk, headersOk, methodsOk)(router))) +} + +func GUI() { + //here, run webserver + log.Println("webserver in port " + config.WebPort) + http.Handle("/", http.FileServer(http.Dir("./webapp"))) + http.ListenAndServe(":"+config.WebPort, nil) +}
A
mongoOperations.go
@@ -0,0 +1,26 @@
+package main + +import ( + mgo "gopkg.in/mgo.v2" +) + +func getSession() (*mgo.Session, error) { + session, err := mgo.Dial("mongodb://" + config.Mongodb.IP) + if err != nil { + panic(err) + } + //defer session.Close() + + // Optional. Switch the session to a monotonic behavior. + session.SetMode(mgo.Monotonic, true) + + // Optional. Switch the session to a monotonic behavior. + session.SetMode(mgo.Monotonic, true) + + return session, err +} +func getCollection(session *mgo.Session, collection string) *mgo.Collection { + + c := session.DB(config.Mongodb.Database).C(collection) + return c +}
A
readConfig.go
@@ -0,0 +1,26 @@
+package main + +import ( + "encoding/json" + "io/ioutil" +) + +//Config reads the config +type Config struct { + APIPort string `json:"apiport"` + WebPort string `json:"webport"` + Mongodb MongoConfig `json:"mongodb"` +} +type MongoConfig struct { + IP string `json:"ip"` + Database string `json:"database"` +} + +var config Config + +func readConfig(path string) { + file, err := ioutil.ReadFile(path) + check(err) + content := string(file) + json.Unmarshal([]byte(content), &config) +}
A
restConfig.go
@@ -0,0 +1,47 @@
+package main + +import ( + "log" + "net/http" + "time" + + "github.com/gorilla/mux" +) + +type Route struct { + Name string + Method string + Pattern string + HandlerFunc http.HandlerFunc +} + +func Logger(inner http.Handler, name string) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + start := time.Now() + + inner.ServeHTTP(w, r) + + log.Printf( + "%s\t%s\t%s\t%s", + r.Method, + r.RequestURI, + name, + time.Since(start), + ) + }) +} +func NewRouter() *mux.Router { + router := mux.NewRouter().StrictSlash(true) + for _, route := range routes { + var handler http.Handler + handler = route.HandlerFunc + handler = Logger(handler, route.Name) + + router. + Methods(route.Method). + Path(route.Pattern). + Name(route.Name). + Handler(handler) + } + return router +}
A
restRoutes.go
@@ -0,0 +1,24 @@
+package main + +type Routes []Route + +var routes = Routes{ + Route{ + "Index", + "GET", + "/", + Index, + }, + Route{ + "Signup", + "POST", + "/signup", + Signup, + }, + Route{ + "Login", + "POST", + "/login", + Login, + }, +}
A
tokens.go
@@ -0,0 +1,49 @@
+package main + +import ( + "fmt" + "time" + + jwt "github.com/dgrijalva/jwt-go" +) + +const ( + signingKey = "this is the secret signing key" +) + +var createdToken string + +func initializeToken() { + var err error + createdToken, err = newToken() + if err != nil { + fmt.Println("Creating token failed") + } +} + +func newToken() (string, error) { + signingKeyB := []byte(signingKey) + // Create the token + token := jwt.New(jwt.SigningMethodHS256) + // Set some claims + claims := make(jwt.MapClaims) + claims["foo"] = "bar" + claims["exp"] = time.Now().Add(time.Hour * 72).Unix() + token.Claims = claims + + // Sign and get the complete encoded token as a string + tokenString, err := token.SignedString(signingKeyB) + return tokenString, err +} + +func parseToken(myToken string, myKey string) { + token, err := jwt.Parse(myToken, func(token *jwt.Token) (interface{}, error) { + return []byte(myKey), nil + }) + + if err == nil && token.Valid { + fmt.Println("Your token is valid. I like your style.") + } else { + fmt.Println("This token is terrible! I cannot accept this.") + } +}
A
webapp/app.js
@@ -0,0 +1,88 @@
+'use strict'; + +var apiurl = "http://127.0.0.1:3000/"; + +angular.module('app', [ + 'ngRoute', + 'ngMessages', + 'toastr', + 'chart.js', + 'app.navbar', + 'app.signup', + 'app.login', + 'app.main', + 'app.newmodel', + 'app.profile' +]). +config(['$locationProvider', '$routeProvider', function($locationProvider, $routeProvider) { + $locationProvider.hashPrefix('!'); + /*$routeProvider.otherwise({ + redirectTo: '/main' + });*/ + + if((localStorage.getItem('dblog_user'))) + { + console.log(window.location.hash); + if((window.location.hash==='#!/login')||(window.location.hash==='#!/signup')) + { + window.location='#!/main'; + } + + $routeProvider.otherwise({redirectTo: '/main'}); + }else{ + if((window.location!=='#!/login')||(window.location!=='#!/signup')||(window.location!=='#!/main')) + { + console.log('app, user no logged'); + + localStorage.removeItem('dblog_user'); + localStorage.removeItem('dblog_user'); + window.location='#!/main'; + $routeProvider.otherwise({redirectTo: '/main'}); + } + } + }]) + .config(function(toastrConfig) { + angular.extend(toastrConfig, { + autoDismiss: false, + containerId: 'toast-container', + maxOpened: 0, + newestOnTop: true, + positionClass: 'toast-bottom-right', + preventDuplicates: false, + preventOpenDuplicates: false, + target: 'body' + }); + }) + .factory('httpInterceptor', function httpInterceptor() { + return { + request: function(config) { + return config; + }, + + requestError: function(config) { + return config; + }, + + response: function(res) { + return res; + }, + + responseError: function(res) { + return res; + } + }; + }) + .factory('api', function($http) { + return { + init: function() { + var dblog_user = JSON.parse(localStorage.getItem('dblog_user')); + if (dblog_user) { + $http.defaults.headers.common['Authorization'] = dblog_user.token; + $http.defaults.headers.post['Authorization'] = dblog_user.token; + } + } + }; + }) + .run(function(api) { + api.init(); + });
A
webapp/bower.json
@@ -0,0 +1,19 @@
+{ + "name": "ipfs-ai-models-market", + "description": "", + "version": "0.0.0", + "homepage": "", + "license": "GNU", + "private": true, + "dependencies": { + "angular": "^1.6.2", + "angular-route": "^1.6.1", + "angular-messages": "^1.6.5", + "angular-bootstrap-material": "abm#^0.1.4", + "angular-bootstrap": "^2.5.0", + "components-font-awesome": "^4.7.0", + "angular-toastr": "^2.1.1", + "cssMaterialColors": "*", + "angular-chart.js": "^1.1.1" + } +}
A
webapp/css/own.css
@@ -0,0 +1,5 @@
+.o_nav { + background: #ffffff!important; + color: #000000!important; + /*border-bottom: 2px solid #4DD0E1!important;*/ +}
A
webapp/index.html
@@ -0,0 +1,73 @@
+<!DOCTYPE html> +<html lang="en" ng-app="app" ng-cloak> + +<head> + <meta charset="utf-8"> + <title>ipfs-ai-models-market</title> + <meta name="viewport" content="width=device-width, initial-scale=1"> + + <link rel="icon" type="image/png" href="img/icon.png"> + + <!-- Fonts --> + <link href="https://fonts.googleapis.com/css?family=Open+Sans|Overpass+Mono:700|Raleway:700" rel="stylesheet"> + + <!-- Bootstrap --> + <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous"> + + + <link rel="stylesheet" href="bower_components/components-font-awesome/css/font-awesome.min.css"> + + <link rel="stylesheet" href="css/own.css"> + + <link href="bower_components/cssMaterialColors/colors.css" rel="stylesheet"> +</head> + +<body ng-app="webapp"> + <div ng-include="'views/navbar.html'"></div> + <br><br><br><br> + <div ng-view></div> + + + +<!-- ELECTRON +Insert this line above script imports +Works for both browser and electron with the same code --> +<script>if (typeof module === 'object') {window.module = module; module = undefined;}</script> + + + <!-- Angular js --> + <script src="bower_components/angular/angular.js"></script> + <script src="bower_components/angular-route/angular-route.js"></script> + <script src="bower_components/angular-messages/angular-messages.js"></script> + + + <!-- Bootstrap --> + <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script> + <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script> + <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script> + + <!-- Angular Chart --> + <script src="bower_components/chart.js/dist/Chart.min.js"></script> + <script src="bower_components/angular-chart.js/dist/angular-chart.min.js"></script> + + <!-- toastr --> + <link rel="stylesheet" type="text/css" href="bower_components/angular-toastr/dist/angular-toastr.css" /> + <script type="text/javascript" src="bower_components/angular-toastr/dist/angular-toastr.tpls.js"></script> + + <!-- app's js --> + <script src="app.js"></script> + <script src="views/navbar.js"></script> + <script src="views/signup/signup.js"></script> + <script src="views/login/login.js"></script> + <script src="views/main/main.js"></script> + <script src="views/newmodel/newmodel.js"></script> + <script src="views/profile/profile.js"></script> + + +<!-- ELECTRON +Insert this line after script imports --> +<script>if (window.module) module = window.module;</script> + +</body> + +</html>
A
webapp/package.json
@@ -0,0 +1,13 @@
+{ + "name": "decentralized-blogging-platform", + "version": "1.0.0", + "description": "", + "scripts": { + "postinstall": "bower install", + "prestart": "npm install", + "start": "http-server" + }, + "dependencies": { + "bootstrap": "^4.0.0" + } +}
A
webapp/views/login/login.html
@@ -0,0 +1,35 @@
+<div class="container" style="margin-top: -60px;"> + <div class="row"> + <div class="col-sm-3"> + + </div> + <div class="col-sm-6"> + <div class="card"> + <div class="card-body"> + <h4 class="card-title"> + Login + </h4> + <div class="form-group"> + <input ng-model="user.email" type="email" class="form-control" placeholder="Email"> + </div> + <div class="form-group"> + <input ng-model="user.password" type="password" class="form-control" placeholder="Password"> + </div> + <div class="row"> + <div class="col-sm-6"> + <a href="#!/signup" class="btn btn-raised btn-block c_o_pink300">Signup</a> + </div> + <div class="col-sm-6"> + <div ng-click="login()" class="btn btn-raised btn-block c_o_cyan300 pull-right">Login</div> + </div> + </div> + </div> + </div> + </div> + + + <div class="col-sm-3"> + + </div> + </div> +</div>
A
webapp/views/login/login.js
@@ -0,0 +1,36 @@
+'use strict'; + +angular.module('app.login', ['ngRoute']) + + .config(['$routeProvider', function($routeProvider) { + $routeProvider.when('/login', { + templateUrl: 'views/login/login.html', + controller: 'LoginCtrl' + }); + }]) + + .controller('LoginCtrl', function($scope, $rootScope, $http, $routeParams, toastr) { + $rootScope.server = "" + $scope.user = {}; + + $scope.login = function() { + $http({ + url: apiurl + 'login', + method: "POST", + headers: { + "Content-Type": undefined + }, + data: $scope.user + }) + .then(function(data) { + console.log("data: "); + console.log(data.data); + localStorage.setItem("dblog_user", JSON.stringify(data.data)); + window.location.reload(); + }, + function(data) { + console.log(data); + }); + + }; + });
A
webapp/views/main/main.html
@@ -0,0 +1,14 @@
+<div class="container"> + <div class="row"> + <div class="col-sm-3"> + <div class="card" style="width: 18rem;"> + <img class="card-img-top" ng-src="http://localhost:8080/ipfs/QmUE6hhNsyUA5emj2dviVDNYK7mSbPeZmRKeCYthmtemeA" alt="Card image cap"> + <div class="card-body"> + <h5 class="card-title">Post1</h5> + <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p> + <a href="#" class="btn btn-primary">Go somewhere</a> + </div> + </div> + </div> + </div> +</div>
A
webapp/views/main/main.js
@@ -0,0 +1,16 @@
+'use strict'; + +angular.module('app.main', ['ngRoute']) + + .config(['$routeProvider', function($routeProvider) { + $routeProvider.when('/main', { + templateUrl: 'views/main/main.html', + controller: 'MainCtrl' + }); + }]) + + .controller('MainCtrl', function($scope, $rootScope, $http) { + + + + });
A
webapp/views/newmodel/newmodel.html
@@ -0,0 +1,18 @@
+<div class="container"> + <div class="row"> + <div class="col-sm-6 col-sm-offset-3"> + <div class="card"> + <div class="card-body"> + <h4>New model</h4> + <input ng-model="model.title" placeholder="Title" type="text" class="form-control"> + <input ng-model="model.description" placeholder="Description" type="text" class="form-control"> + + <input type="file" file-model="file"/> + + <input ng-model="model.accuracy" placeholder="Accuracy" type="text" class="form-control"> + <a ng-click="upload()" class="btn btn-raised pull-right c_o_pink300">Upload</a> + </div> + </div> + </div> + </div> +</div>
A
webapp/views/newmodel/newmodel.js
@@ -0,0 +1,79 @@
+'use strict'; + +angular.module('app.newmodel', ['ngRoute']) + + .config(['$routeProvider', function($routeProvider) { + $routeProvider.when('/newmodel', { + templateUrl: 'views/newmodel/newmodel.html', + controller: 'NewModelCtrl' + }); + }]) + + .controller('NewModelCtrl', function($scope, $rootScope, $http, toastr) { + + $scope.file = {}; + + $scope.upload = function() { + console.log("upload model"); + var formdata = new FormData(); + formdata.append("file", $scope.file); + + //add the file to ipfs + /*$http({ + url: ipfs_url + 'add', + method: "POST", + headers: { + "Content-Type": undefined + }, + data: formdata + }) + .then(function(data) { + console.log("data: "); + console.log(data.data); + toastr.success("Model added to IPFS"); + }, + function(data) { + console.log(data); + toastr.error("Error adding Model to IPFS"); + });*/ + + //add the data to userdata + $http({ + url: clienturl + 'model', + method: "POST", + headers: { + "Content-Type": undefined + }, + data: $scope.model + }) + .then(function(data) { + console.log("data: "); + console.log(data.data); + window.location="/"; + toastr.success("Model uploaded"); + }, + function(data) { + console.log(data); + }); + + + }; + + + + }) + .directive('fileModel', ['$parse', function($parse) { + //directive code from https://www.tutorialspoint.com/angularjs/angularjs_upload_file.htm + return { + restrict: 'A', + link: function(scope, element, attrs) { + var model = $parse(attrs.fileModel); + var modelSetter = model.assign; + element.bind('change', function() { + scope.$apply(function() { + modelSetter(scope, element[0].files[0]); + }); + }); + } + }; + }]);
A
webapp/views/profile/profile.html
@@ -0,0 +1,31 @@
+<div class="container"> + <div class="row"> + <div class="col-sm-4"> + <div ng-include="'views/user_template.html'"></div> + </div> + <div class="col-sm-8"> + <div class="card"> + <table class="table table-striped table-hover "> + <thead> + <tr> + <th>#</th> + <th>Title</th> + <th>Description</th> + <th>Accuracy</th> + <th>Rating</th> + </tr> + </thead> + <tbody> + <tr ng-repeat="model in user.models"> + <td>1</td> + <td>{{model.title}}</td> + <td>{{model.description}}</td> + <td>{{model.accuracy}}</td> + <td>{{model.rating}}</td> + </tr> + </tbody> + </table> + </div> + </div> + </div> +</div>
A
webapp/views/profile/profile.js
@@ -0,0 +1,24 @@
+'use strict'; + +angular.module('app.profile', ['ngRoute']) + + .config(['$routeProvider', function($routeProvider) { + $routeProvider.when('/profile', { + templateUrl: 'views/profile/profile.html', + controller: 'ProfileCtrl' + }); + }]) + + .controller('ProfileCtrl', function($scope, $rootScope, $http) { + + $http.get(clienturl + 'user') + .then(function(data) { + console.log('data success'); + console.log(data); + $scope.user = data.data; + localStorage.setItem("ai_user", JSON.stringify($scope.user)); + + }, function(data) { + console.log('no user'); + }); + });
A
webapp/views/signup/signup.html
@@ -0,0 +1,38 @@
+<div class="container" style="margin-top: -80px;"> + <div class="row"> + <div class="col-sm-3"> + + </div> + <div class="col-sm-6"> + <div class="card"> + <div class="card-body"> + <h4 class="card-title"> + Signup + </h4> + <div class="form-group"> + <input ng-model="user.username" class="form-control" placeholder="Username"> + </div> + <div class="form-group"> + <input ng-model="user.email" type="email" class="form-control" placeholder="Email"> + </div> + <div class="form-group"> + <input ng-model="user.password" type="password" class="form-control" placeholder="Password"> + </div> + <div class="row"> + <div class="col-sm-6"> + <a href="#!/login" class="btn btn-raised btn-block c_o_blue300">Cancel</a> + </div> + <div class="col-sm-6"> + <div ng-click="signup()" class="btn btn-raised btn-block c_o_green300 pull-right">Signup</div> + </div> + </div> + </div> + </div> + </div> + + + <div class="col-sm-3"> + + </div> + </div> +</div>
A
webapp/views/signup/signup.js
@@ -0,0 +1,34 @@
+'use strict'; + +angular.module('app.signup', ['ngRoute']) + +.config(['$routeProvider', function($routeProvider) { + $routeProvider.when('/signup', { + templateUrl: 'views/signup/signup.html', + controller: 'SignupCtrl' + }); +}]) + +.controller('SignupCtrl', function($scope, $http, $routeParams, $rootScope) { + $scope.signup = function() { + console.log('Doing signup', $scope.user); + $http({ + url: apiurl + 'signup', + method: "POST", + headers: { + "Content-Type": undefined + }, + data: $scope.user + }) + .then(function(data) { + console.log("data: "); + console.log(data.data); + window.location="/#!/login"; + + }, + function(data) { + console.log(data); + }); + + }; +});