diff --git a/README.md b/README.md index 4862f5df..70553b3f 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,6 @@ -[![Deploy](https://www.herokucdn.com/deploy/button.png)](https://heroku.com/deploy) +# React Learning Example -# React Tutorial - -This is the React comment box example from [the React tutorial](http://facebook.github.io/react/docs/tutorial.html). - -## To use - -There are several simple server implementations included. They all serve static files from `public/` and handle requests to `/api/comments` to fetch or add data. Start a server with one of the following: +This is a example code that inheriented from React tutorial. ### Node @@ -15,35 +9,6 @@ npm install node server.js ``` -### Python - -```sh -pip install -r requirements.txt -python server.py -``` - -### Ruby -```sh -ruby server.rb -``` - -### PHP -```sh -php server.php -``` - -### Go -```sh -go run server.go -``` - -### Perl - -```sh -cpan Mojolicious -perl server.pl -``` - And visit . Try opening multiple tabs! ## Changing the port diff --git a/chatRecords.json b/chatRecords.json new file mode 100644 index 00000000..e358ac3f --- /dev/null +++ b/chatRecords.json @@ -0,0 +1,23 @@ +[ + { + "id": 1, + "name": "Pete Hunt", + "body": "Lorem ipsum dolor sit amet, id malorum perpetua has, id eum case appetere.", + "avatarURL": "https://avatars0.githubusercontent.com/u/5420789?v=3&s=460", + "selfChat": false + }, + { + "id": 2, + "name": "Haoyu Hunt", + "body": "Tantas vituperata et pri, eu appareat inimicus eam", + "avatarURL": "https://avatars0.githubusercontent.com/u/5420789?v=3&s=460", + "selfChat": false + }, + { + "id": 3, + "name": "Chen Hunt", + "body": "ius audiam voluptaria qualisque. Sed no feugait accusam. Et sed nostrud invidunt, duo tractatos deterruisset ei, nam in voluptua invenire", + "avatarURL": "https://avatars0.githubusercontent.com/u/5420789?v=3&s=460", + "selfChat": true + } +] \ No newline at end of file diff --git a/comments.json b/comments.json deleted file mode 100644 index 7bef77ad..00000000 --- a/comments.json +++ /dev/null @@ -1,12 +0,0 @@ -[ - { - "id": 1388534400000, - "author": "Pete Hunt", - "text": "Hey there!" - }, - { - "id": 1420070400000, - "author": "Paul O’Shannessy", - "text": "React is *great*!" - } -] diff --git a/public/css/base.css b/public/css/base.css index bf382be3..bd50d25c 100644 --- a/public/css/base.css +++ b/public/css/base.css @@ -1,62 +1,137 @@ -body { - background: #fff; - font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; - font-size: 15px; - line-height: 1.7; - margin: 0; - padding: 30px; +.online-user-list { + border: 1px solid #c7b89e; } - -a { - color: #4183c4; - text-decoration: none; +.avatar-chat { + border: 2px solid #c7b89e; + display: inline-block; } -a:hover { - text-decoration: underline; +.avatar-chat, +.avatar-chat img { + width: 30px; + height: 30px; + -webkit-border-radius: 30px; + /* Saf3+, Chrome */ + border-radius: 30px; + /* Opera 10.5, IE 9 */ + /*-moz-border-radius: 30px; Disabled for FF1+ */ } -code { - background-color: #f8f8f8; - border: 1px solid #ddd; - border-radius: 3px; - font-family: "Bitstream Vera Sans Mono", Consolas, Courier, monospace; - font-size: 12px; - margin: 0 2px; - padding: 0px 5px; +/* Chat in Xlbock*/ +.chat-box { + font-family:'Helvetica Neue',Helvetica, sans-serif; + font-size:14px; + margin:0; } -h1, h2, h3, h4 { - font-weight: bold; - margin: 0 0 15px; - padding: 0; +.chat-container { + width:400px; + display:block; + margin:0 auto; + box-shadow:0 2px 5px rgba(0,0,0,0.4); } -h1 { - border-bottom: 1px solid #ddd; - font-size: 2.5em; - font-weight: bold; - margin: 0 0 15px; - padding: 0; +.chat-box, .enter-message{ + background:#ECECEC; + padding:0 20px; + color:#a1a1a1; } - -h2 { - border-bottom: 1px solid #eee; - font-size: 2em; +.chat-box .message-box{ + padding:18px 0 10px; + clear:both; } - -h3 { - font-size: 1.5em; +.message-box .picture{ + float:left; + width:50px; + display:block; + padding-right:10px; +} +.picture img{ + width:43px; + height:48px; + border-radius:5px; +} +.picture span{ + font-weight:bold; + font-size:12px; + clear:both; + display:block; + text-align:center; + margin-top:3px; +} +.message{ + background:#fff; + display:inline-block; + padding:13px; + width:274px; + border-radius:2px; + box-shadow: 0 1px 1px rgba(0,0,0,.04); + position:relative; +} +.message:before{ + content:""; + position:absolute; + display:block; + left:0; + border-right:6px solid #fff; + border-top: 6px solid transparent; + border-bottom:6px solid transparent; + top:10px; + margin-left:-6px; +} +.message span{ + color:#555; + font-weight:bold; +} +.message p{ + padding-top:5px; +} +.message-box.right-img .picture{ + float:right; + padding:0; + padding-left:10px; +} +.message-box.right-img .picture img{ + float:right; +} +.message-box.right-img .message:before{ + left:100%; + margin-right:6px; + margin-left:0; + border-right:6px solid transparent; + border-left:6px solid #fff; + border-top: 6px solid transparent; + border-bottom:6px solid transparent; } -h4 { - font-size: 1.2em; +.avatar-chat { + display: inline-block; } -p, ul { - margin: 15px 0; +.avatar-chat, +.avatar-chat img { + width: 40px; + height: 40px; + -webkit-border-radius: 40px; + /* Saf3+, Chrome */ + border-radius: 40px; + /* Opera 10.5, IE 9 */ + /*-moz-border-radius: 30px; Disabled for FF1+ */ } -ul { - padding-left: 30px; +/*.enter-message{ + padding:13px 0px; +} +.enter-message input{ + border:none; + padding:10px 12px; + background:#d3d3d3; + width:260px; + border-radius:2px; } +.enter-message a.send{ + padding:10px 15px; + background:#6294c2; + border-radius:2px; + float:right; +}*/ \ No newline at end of file diff --git a/public/index.html b/public/index.html index c6494446..82637e06 100644 --- a/public/index.html +++ b/public/index.html @@ -13,10 +13,6 @@
- - + diff --git a/public/scripts/chat.js b/public/scripts/chat.js new file mode 100644 index 00000000..02fe0e95 --- /dev/null +++ b/public/scripts/chat.js @@ -0,0 +1,171 @@ +/** + * This file provided by Facebook is for non-commercial testing and evaluation + * purposes only. Facebook reserves all rights not expressly granted. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + +var OnlineUserAvatar = React.createClass({ + render: function() { + return ( +
+ +
+ ); + } +}); + +var OnlineUserList = React.createClass({ + render: function() { + var onlineUserListNode = this.props.data.map(function(user) { + return ( + + ); + }); + return ( +
+ {onlineUserListNode} +
+ ); + } +}); + + +// var ChatRecord = React.createClass({ +// render: function() { +// return ( +//
  • +// {this.props.data.body} +//
  • +// ); +// } +// }); + + +var ChatRecordsList = React.createClass({ + render: function() { + return ( +
    +
    +
    +
    +
    + +
    + 10 mins +
    +
    + Bobby Giangeruso +

    Hey Mike, how are you doing?

    +
    +
    +
    +
    +
    + +
    + 2 mins +
    +
    + Mike Moloney +

    Pretty good, Eating nutella, nommommom

    +
    +
    +
    +
    + ); + } +}); + +// var ChatRecordsList = React.createClass({ +// render: function() { +// var chatRecordsNodes = this.props.data.map(function(record) { +// return ( +// +// ); +// }); + +// return ( +//
      +// {chatRecordsNodes} +//
    +// ); +// } +// }); + +var Comment = React.createClass({ + rawMarkup: function() { + var rawMarkup = marked(this.props.children.toString(), {sanitize: true}); + return { __html: rawMarkup }; + }, + + render: function() { + return ( +
    +

    + {this.props.author} +

    + +
    + ); + } +}); + +var CommentBox = React.createClass({ + loadUsersFromServer: function () { + $.ajax({ + url: '/api/users', + dataType: 'json', + cache: false, + success: function(data) { + this.setState({onlineUsersData: data}); + }.bind(this), + error: function(xhr, status, err) { + console.error('/api/users', status, err.toString()); + }.bind(this) + }); + }, + loadChatRecordsFromServer: function () { + $.ajax({ + url: '/api/chatrecords', + dataType: 'json', + cache: false, + success: function(data) { + this.setState({chatRecordsData: data}); + }.bind(this), + error: function(xhr, status, err) { + console.error('/api/chatrecords', status, err.toString()); + }.bind(this) + }); + }, + getInitialState: function() { + return {onlineUsersData: [], chatRecordsData: []}; + }, + componentDidMount: function() { + this.loadUsersFromServer(); + this.loadChatRecordsFromServer(); + setInterval(this.loadUsersFromServer, this.props.pollInterval); + setInterval(this.loadChatRecordsFromServer, this.props.pollInterval); + }, + render: function() { + return ( +
    + + +
    + ); + } +}); + + +ReactDOM.render( + , + document.getElementById('content') +); diff --git a/public/scripts/example.js b/public/scripts/example.js deleted file mode 100644 index c249427a..00000000 --- a/public/scripts/example.js +++ /dev/null @@ -1,146 +0,0 @@ -/** - * This file provided by Facebook is for non-commercial testing and evaluation - * purposes only. Facebook reserves all rights not expressly granted. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -var Comment = React.createClass({ - rawMarkup: function() { - var rawMarkup = marked(this.props.children.toString(), {sanitize: true}); - return { __html: rawMarkup }; - }, - - render: function() { - return ( -
    -

    - {this.props.author} -

    - -
    - ); - } -}); - -var CommentBox = React.createClass({ - loadCommentsFromServer: function() { - $.ajax({ - url: this.props.url, - dataType: 'json', - cache: false, - success: function(data) { - this.setState({data: data}); - }.bind(this), - error: function(xhr, status, err) { - console.error(this.props.url, status, err.toString()); - }.bind(this) - }); - }, - handleCommentSubmit: function(comment) { - var comments = this.state.data; - // Optimistically set an id on the new comment. It will be replaced by an - // id generated by the server. In a production application you would likely - // not use Date.now() for this and would have a more robust system in place. - comment.id = Date.now(); - var newComments = comments.concat([comment]); - this.setState({data: newComments}); - $.ajax({ - url: this.props.url, - dataType: 'json', - type: 'POST', - data: comment, - success: function(data) { - this.setState({data: data}); - }.bind(this), - error: function(xhr, status, err) { - this.setState({data: comments}); - console.error(this.props.url, status, err.toString()); - }.bind(this) - }); - }, - getInitialState: function() { - return {data: []}; - }, - componentDidMount: function() { - this.loadCommentsFromServer(); - setInterval(this.loadCommentsFromServer, this.props.pollInterval); - }, - render: function() { - return ( -
    -

    Comments

    - - -
    - ); - } -}); - -var CommentList = React.createClass({ - render: function() { - var commentNodes = this.props.data.map(function(comment) { - return ( - - {comment.text} - - ); - }); - return ( -
    - {commentNodes} -
    - ); - } -}); - -var CommentForm = React.createClass({ - getInitialState: function() { - return {author: '', text: ''}; - }, - handleAuthorChange: function(e) { - this.setState({author: e.target.value}); - }, - handleTextChange: function(e) { - this.setState({text: e.target.value}); - }, - handleSubmit: function(e) { - e.preventDefault(); - var author = this.state.author.trim(); - var text = this.state.text.trim(); - if (!text || !author) { - return; - } - this.props.onCommentSubmit({author: author, text: text}); - this.setState({author: '', text: ''}); - }, - render: function() { - return ( -
    - - - -
    - ); - } -}); - -ReactDOM.render( - , - document.getElementById('content') -); diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 632a1efa..00000000 --- a/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -Flask==0.10.1 diff --git a/server.go b/server.go deleted file mode 100644 index 2224328d..00000000 --- a/server.go +++ /dev/null @@ -1,110 +0,0 @@ -/** - * This file provided by Facebook is for non-commercial testing and evaluation - * purposes only. Facebook reserves all rights not expressly granted. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -package main - -import ( - "bytes" - "encoding/json" - "fmt" - "io" - "io/ioutil" - "log" - "net/http" - "os" - "sync" - "time" -) - -type comment struct { - ID int64 `json:"id"` - Author string `json:"author"` - Text string `json:"text"` -} - -const dataFile = "./comments.json" - -var commentMutex = new(sync.Mutex) - -// Handle comments -func handleComments(w http.ResponseWriter, r *http.Request) { - // Since multiple requests could come in at once, ensure we have a lock - // around all file operations - commentMutex.Lock() - defer commentMutex.Unlock() - - // Stat the file, so we can find its current permissions - fi, err := os.Stat(dataFile) - if err != nil { - http.Error(w, fmt.Sprintf("Unable to stat the data file (%s): %s", dataFile, err), http.StatusInternalServerError) - return - } - - // Read the comments from the file. - commentData, err := ioutil.ReadFile(dataFile) - if err != nil { - http.Error(w, fmt.Sprintf("Unable to read the data file (%s): %s", dataFile, err), http.StatusInternalServerError) - return - } - - switch r.Method { - case "POST": - // Decode the JSON data - var comments []comment - if err := json.Unmarshal(commentData, &comments); err != nil { - http.Error(w, fmt.Sprintf("Unable to Unmarshal comments from data file (%s): %s", dataFile, err), http.StatusInternalServerError) - return - } - - // Add a new comment to the in memory slice of comments - comments = append(comments, comment{ID: time.Now().UnixNano() / 1000000, Author: r.FormValue("author"), Text: r.FormValue("text")}) - - // Marshal the comments to indented json. - commentData, err = json.MarshalIndent(comments, "", " ") - if err != nil { - http.Error(w, fmt.Sprintf("Unable to marshal comments to json: %s", err), http.StatusInternalServerError) - return - } - - // Write out the comments to the file, preserving permissions - err := ioutil.WriteFile(dataFile, commentData, fi.Mode()) - if err != nil { - http.Error(w, fmt.Sprintf("Unable to write comments to data file (%s): %s", dataFile, err), http.StatusInternalServerError) - return - } - - w.Header().Set("Content-Type", "application/json") - w.Header().Set("Cache-Control", "no-cache") - io.Copy(w, bytes.NewReader(commentData)) - - case "GET": - w.Header().Set("Content-Type", "application/json") - w.Header().Set("Cache-Control", "no-cache") - // stream the contents of the file to the response - io.Copy(w, bytes.NewReader(commentData)) - - default: - // Don't know the method, so error - http.Error(w, fmt.Sprintf("Unsupported method: %s", r.Method), http.StatusMethodNotAllowed) - } -} - -func main() { - port := os.Getenv("PORT") - if port == "" { - port = "3000" - } - http.HandleFunc("/api/comments", handleComments) - http.Handle("/", http.FileServer(http.Dir("./public"))) - log.Println("Server started: http://localhost:" + port) - log.Fatal(http.ListenAndServe(":"+port, nil)) -} diff --git a/server.js b/server.js index ac87898a..43cc2be4 100644 --- a/server.js +++ b/server.js @@ -10,13 +10,17 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + + + var fs = require('fs'); var path = require('path'); var express = require('express'); var bodyParser = require('body-parser'); var app = express(); -var COMMENTS_FILE = path.join(__dirname, 'comments.json'); +var USERS_FILE = path.join(__dirname, 'users.json'); +var CHATRECORDS_FILE = path.join(__dirname, 'chatRecords.json'); app.set('port', (process.env.PORT || 3000)); @@ -24,8 +28,9 @@ app.use('/', express.static(path.join(__dirname, 'public'))); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({extended: true})); -app.get('/api/comments', function(req, res) { - fs.readFile(COMMENTS_FILE, function(err, data) { + +app.get('/api/users', function(req, res) { + fs.readFile(USERS_FILE, function(err, data) { if (err) { console.error(err); process.exit(1); @@ -35,30 +40,14 @@ app.get('/api/comments', function(req, res) { }); }); -app.post('/api/comments', function(req, res) { - fs.readFile(COMMENTS_FILE, function(err, data) { +app.get('/api/chatrecords', function(req, res) { + fs.readFile(CHATRECORDS_FILE, function(err, data) { if (err) { console.error(err); process.exit(1); } - var comments = JSON.parse(data); - // NOTE: In a real implementation, we would likely rely on a database or - // some other approach (e.g. UUIDs) to ensure a globally unique id. We'll - // treat Date.now() as unique-enough for our purposes. - var newComment = { - id: Date.now(), - author: req.body.author, - text: req.body.text, - }; - comments.push(newComment); - fs.writeFile(COMMENTS_FILE, JSON.stringify(comments, null, 4), function(err) { - if (err) { - console.error(err); - process.exit(1); - } - res.setHeader('Cache-Control', 'no-cache'); - res.json(comments); - }); + res.setHeader('Cache-Control', 'no-cache'); + res.json(JSON.parse(data)); }); }); diff --git a/server.php b/server.php deleted file mode 100644 index 6b8880c8..00000000 --- a/server.php +++ /dev/null @@ -1,52 +0,0 @@ - round(microtime(true) * 1000), - 'author' => $_POST['author'], - 'text' => $_POST['text'] - ]; - - $comments = json_encode($commentsDecoded, JSON_PRETTY_PRINT); - file_put_contents('comments.json', $comments); - } - header('Content-Type: application/json'); - header('Cache-Control: no-cache'); - echo $comments; - } else { - return false; - } -} diff --git a/server.pl b/server.pl deleted file mode 100644 index 517e1621..00000000 --- a/server.pl +++ /dev/null @@ -1,36 +0,0 @@ -# This file provided by Facebook is for non-commercial testing and evaluation -# purposes only. Facebook reserves all rights not expressly granted. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -# FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -use Time::HiRes qw(gettimeofday); -use Mojolicious::Lite; -use Mojo::JSON qw(encode_json decode_json); - -app->static->paths->[0] = './public'; - -any '/' => sub { $_[0]->reply->static('index.html') }; - -any [qw(GET POST)] => '/api/comments' => sub { - my $self = shift; - my $comments = decode_json (do { local(@ARGV,$/) = 'comments.json';<> }); - - if ($self->req->method eq 'POST') - { - push @$comments, { - id => int(gettimeofday * 1000), - author => $self->param('author'), - text => $self->param('text'), - }; - open my $FILE, '>', 'comments.json'; - print $FILE encode_json($comments); - } - $self->render(json => $comments); -}; -my $port = $ENV{PORT} || 3000; -app->start('daemon', '-l', "http://*:$port"); diff --git a/server.py b/server.py deleted file mode 100644 index 451fbacd..00000000 --- a/server.py +++ /dev/null @@ -1,36 +0,0 @@ -# This file provided by Facebook is for non-commercial testing and evaluation -# purposes only. Facebook reserves all rights not expressly granted. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -# FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -import json -import os -import time -from flask import Flask, Response, request - -app = Flask(__name__, static_url_path='', static_folder='public') -app.add_url_rule('/', 'root', lambda: app.send_static_file('index.html')) - -@app.route('/api/comments', methods=['GET', 'POST']) -def comments_handler(): - - with open('comments.json', 'r') as file: - comments = json.loads(file.read()) - - if request.method == 'POST': - newComment = request.form.to_dict() - newComment['id'] = int(time.time() * 1000) - comments.append(newComment) - - with open('comments.json', 'w') as file: - file.write(json.dumps(comments, indent=4, separators=(',', ': '))) - - return Response(json.dumps(comments), mimetype='application/json', headers={'Cache-Control': 'no-cache'}) - -if __name__ == '__main__': - app.run(port=int(os.environ.get("PORT",3000))) diff --git a/server.rb b/server.rb deleted file mode 100644 index eed401ae..00000000 --- a/server.rb +++ /dev/null @@ -1,46 +0,0 @@ -# This file provided by Facebook is for non-commercial testing and evaluation -# purposes only. Facebook reserves all rights not expressly granted. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -# FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -require 'webrick' -require 'json' - -port = ENV['PORT'].nil? ? 3000 : ENV['PORT'].to_i - -puts "Server started: http://localhost:#{port}/" - -root = File.expand_path './public' -server = WEBrick::HTTPServer.new Port: port, DocumentRoot: root - -server.mount_proc '/api/comments' do |req, res| - comments = JSON.parse(File.read('./comments.json', encoding: 'UTF-8')) - - if req.request_method == 'POST' - # Assume it's well formed - comment = { id: (Time.now.to_f * 1000).to_i } - req.query.each do |key, value| - comment[key] = value.force_encoding('UTF-8') - end - comments << comment - File.write( - './comments.json', - JSON.pretty_generate(comments, indent: ' '), - encoding: 'UTF-8' - ) - end - - # always return json - res['Content-Type'] = 'application/json' - res['Cache-Control'] = 'no-cache' - res.body = JSON.generate(comments) -end - -trap('INT') { server.shutdown } - -server.start diff --git a/users.json b/users.json new file mode 100644 index 00000000..5e7528b8 --- /dev/null +++ b/users.json @@ -0,0 +1,17 @@ +[ + { + "id": 1, + "name": "Pete Hunt", + "avatarURL": "https://avatars0.githubusercontent.com/u/5420789?v=3&s=460" + }, + { + "id": 2, + "name": "Haoyu Hunt", + "avatarURL": "https://avatars0.githubusercontent.com/u/5420789?v=3&s=460" + }, + { + "id": 3, + "name": "Chen Hunt", + "avatarURL": "https://avatars0.githubusercontent.com/u/5420789?v=3&s=460" + } +] \ No newline at end of file