implemented add post - todo create paragraphs
parent
a54d94f6ad
commit
3fec54ae75
|
|
@ -5,7 +5,7 @@ Licence: GPLv3
|
|||
"""
|
||||
|
||||
from flask import Flask
|
||||
from flask.ext.sqlalchemy import SQLAlchemy
|
||||
from flask_sqlalchemy import SQLAlchemy
|
||||
|
||||
|
||||
app = Flask(__name__,static_url_path='',static_folder='build')
|
||||
|
|
@ -16,5 +16,4 @@ app.config.from_object('app.configuration.DevelopmentConfig')
|
|||
#app.config.from_object('configuration.TestingConfig')
|
||||
|
||||
db = SQLAlchemy(app) #flask-sqlalchemy
|
||||
|
||||
from app import views, models
|
||||
|
|
|
|||
|
|
@ -11,10 +11,11 @@ class Config(object):
|
|||
DEBUG = False
|
||||
TESTING = False
|
||||
DATABASE_URI = 'sqlite:///application.db'
|
||||
SQLALCHEMY_DATABASE_URI = 'sqlite:///application.db'
|
||||
BOOTSTRAP_FONTAWESOME = True
|
||||
SECRET_KEY = "MINHACHAVESECRETA"
|
||||
SECRET_KEY = "BLOGAPPSECRETYO"
|
||||
CSRF_ENABLED = True
|
||||
|
||||
SQLALCHEMY_TRACK_MODIFICATIONS = False
|
||||
#Get your reCaptche key on: https://www.google.com/recaptcha/admin/create
|
||||
#RECAPTCHA_PUBLIC_KEY = "6LffFNwSAAAAAFcWVy__EnOCsNZcG2fVHFjTBvRP"
|
||||
#RECAPTCHA_PRIVATE_KEY = "6LffFNwSAAAAAO7UURCGI7qQ811SOSZlgU69rvv7"
|
||||
|
|
@ -23,6 +24,7 @@ class ProductionConfig(Config):
|
|||
DATABASE_URI = 'mysql://user@localhost/foo'
|
||||
|
||||
class DevelopmentConfig(Config):
|
||||
SQLALCHEMY_DATABASE_URI = 'sqlite:///:memory:'
|
||||
DEBUG = True
|
||||
|
||||
class TestingConfig(Config):
|
||||
|
|
|
|||
18
app/forms.py
18
app/forms.py
|
|
@ -1,18 +0,0 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
"""
|
||||
Python Aplication Template
|
||||
Licence: GPLv3
|
||||
"""
|
||||
|
||||
from flask.ext.wtf import Form, TextField, TextAreaField, DateTimeField, PasswordField
|
||||
from flask.ext.wtf import Required
|
||||
|
||||
class ExampleForm(Form):
|
||||
title = TextField(u'Título', validators = [Required()])
|
||||
content = TextAreaField(u'Conteúdo')
|
||||
date = DateTimeField(u'Data', format='%d/%m/%Y %H:%M')
|
||||
#recaptcha = RecaptchaField(u'Recaptcha')
|
||||
|
||||
class LoginForm(Form):
|
||||
user = TextField(u'Usuário', validators = [Required()])
|
||||
password = PasswordField(u'Senha', validators = [Required()])
|
||||
|
|
@ -9,31 +9,46 @@ from app import db
|
|||
class Post(db.Model):
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
title = db.Column(db.String(80))
|
||||
body = db.Column(db.Text)
|
||||
pub_date = db.Column(db.DateTime)
|
||||
content = db.Column(db.Text)
|
||||
# pub_date = db.Column(db.DateTime)
|
||||
|
||||
category_id = db.Column(db.Integer, db.ForeignKey('category.id'))
|
||||
category = db.relationship('Category',
|
||||
backref=db.backref('posts', lazy='dynamic'))
|
||||
|
||||
def __init__(self, title, body, category, pub_date=None):
|
||||
def __init__(self, title,content, pub_date=None):
|
||||
self.title = title
|
||||
self.body = body
|
||||
if pub_date is None:
|
||||
pub_date = datetime.utcnow()
|
||||
self.pub_date = pub_date
|
||||
self.category = category
|
||||
self.content = content
|
||||
# if pub_date is None:
|
||||
# pub_date = datetime.utcnow()
|
||||
# self.pub_date = pub_date
|
||||
# paragraphs = text.split('\n\n')
|
||||
# self.paragraphs = paragraphs
|
||||
|
||||
def __repr__(self):
|
||||
return '<Post %r>' % self.title
|
||||
|
||||
|
||||
class Category(db.Model):
|
||||
class Paragraph(db.Model):
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
name = db.Column(db.String(50))
|
||||
body = db.Column(db.Text)
|
||||
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
post_id = db.Column(db.Integer, db.ForeignKey('post.id'))
|
||||
|
||||
def __init__(self, body,post_id):
|
||||
self.body = body
|
||||
self.post_id = post_id
|
||||
|
||||
def __repr__(self):
|
||||
return '<Category %r>' % self.name
|
||||
return '<Post %r>' % self.title
|
||||
|
||||
class Comment(db.Model):
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
name = db.Column(db.String(50))
|
||||
message = db.Column(db.String(140))
|
||||
paragraph_id = db.Column(db.Integer, db.ForeignKey('paragraph.id'))
|
||||
db.relationship('Paragraph',backref=db.backref('comments', lazy='dynamic'))
|
||||
|
||||
def __init__(self, name,message):
|
||||
self.name = name
|
||||
self.message = message
|
||||
|
||||
def __repr__(self):
|
||||
return '<Comment %r>' % self.name
|
||||
|
||||
db.create_all()
|
||||
|
|
|
|||
32
app/views.py
32
app/views.py
|
|
@ -4,19 +4,31 @@ Python Aplication Template
|
|||
Licence: GPLv3
|
||||
"""
|
||||
|
||||
from flask import url_for, redirect, render_template, flash, g, session
|
||||
from app import app
|
||||
from flask import request
|
||||
from flask_restless import APIManager
|
||||
from app import app,db
|
||||
from models import Post,Paragraph,Comment
|
||||
|
||||
# Create the Flask-Restless API manager.
|
||||
manager = APIManager(app, flask_sqlalchemy_db=db)
|
||||
|
||||
# Create API endpoints, which will be available at /api/<tablename> by
|
||||
# default. Allowed HTTP methods can be specified as well.
|
||||
manager.create_api(Post, methods=['GET', 'POST', 'DELETE'])
|
||||
manager.create_api(Paragraph, methods=['GET'])
|
||||
manager.create_api(Comment, methods=['GET','POST'])
|
||||
|
||||
|
||||
@app.route('/')
|
||||
def index():
|
||||
return app.send_static_file('index.html')
|
||||
|
||||
@app.route('/api/addpost',methods=['POST'])
|
||||
def addpost():
|
||||
return 'Post Added'
|
||||
|
||||
@app.route('/api/listposts')
|
||||
def listposts():
|
||||
return 'Post Added'
|
||||
#
|
||||
# @app.route('/api/addpost',methods=['POST'])
|
||||
# def addpost():
|
||||
# return 'Post Added'
|
||||
#
|
||||
# @app.route('/api/listposts')
|
||||
# def listposts():
|
||||
# return 'Post Added'
|
||||
|
||||
# ====================
|
||||
|
|
|
|||
|
|
@ -77,7 +77,9 @@ module.exports = function(proxy, allowedHost) {
|
|||
disableDotRule: true,
|
||||
},
|
||||
public: allowedHost,
|
||||
proxy,
|
||||
proxy: {
|
||||
"/api":"http://localhost:5000/"
|
||||
},
|
||||
setup(app) {
|
||||
// This lets us open files from the runtime error overlay.
|
||||
app.use(errorOverlayMiddleware());
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -14,6 +14,7 @@
|
|||
"react-router": "^4.1.2",
|
||||
"react-router-dom": "^4.1.2",
|
||||
"react-semantic-ui": "^0.2.0",
|
||||
"semantic-ui-css": "^2.2.12",
|
||||
"semantic-ui-react": "^0.71.3",
|
||||
"yarn": "^0.27.5"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -29,6 +29,8 @@ const paths = require('../config/paths');
|
|||
const config = require('../config/webpack.config.dev');
|
||||
const createDevServerConfig = require('../config/webpackDevServer.config');
|
||||
|
||||
const child_process = require('child_process');
|
||||
|
||||
const useYarn = fs.existsSync(paths.yarnLockFile);
|
||||
const isInteractive = process.stdout.isTTY;
|
||||
|
||||
|
|
@ -72,6 +74,9 @@ choosePort(HOST, DEFAULT_PORT)
|
|||
clearConsole();
|
||||
}
|
||||
console.log(chalk.cyan('Starting the development server...\n'));
|
||||
child_process.spawn('python',['run.py'],{
|
||||
stdio:'inherit'
|
||||
});
|
||||
openBrowser(urls.localUrlForBrowser);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,5 @@ export const App: React.StatelessComponent<{}> = (props) => {
|
|||
<Header />
|
||||
{props.children}
|
||||
</div>
|
||||
|
||||
);
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,79 +0,0 @@
|
|||
import * as React from 'react';
|
||||
|
||||
export const About: React.StatelessComponent<{}> = () => {
|
||||
return (
|
||||
<div className="row about-page">
|
||||
<h1 className="jumbotron">03 Navigation</h1>
|
||||
|
||||
<div className="col-xs-12">
|
||||
<h1>
|
||||
<small>
|
||||
This sample takes as starting point sample "02 Components".
|
||||
</small>
|
||||
</h1>
|
||||
<div className="col-xs-12">
|
||||
<h3>
|
||||
<small>
|
||||
We are adding page navigation to this project:
|
||||
</small>
|
||||
</h3>
|
||||
<ul>
|
||||
<li><h3><small>We have added two pages (about, members).</small></h3></li>
|
||||
<li><h3><small>The user can navigate by clicking on links in a common navbar.</small></h3></li>
|
||||
</ul>
|
||||
<h3>
|
||||
<small>
|
||||
We are using <a target="_blank" href="https://github.com/reactjs/react-router">react-router</a> for the navigation support
|
||||
</small>
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="col-xs-12 top-buffer">
|
||||
<h3>Highlights</h3>
|
||||
<hr />
|
||||
<h3>
|
||||
<small>
|
||||
The most interesting parts worth to take a look
|
||||
</small>
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<div className="col-xs-12 top-buffer">
|
||||
<ul>
|
||||
<li className="top-buffer">
|
||||
<h4><b>Router:</b></h4>
|
||||
<ul className="top-buffer">
|
||||
<li>
|
||||
<h4>
|
||||
index.ts: <small>routes configuration.</small>
|
||||
</h4>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li className="top-buffer">
|
||||
<h4><b>Components:</b></h4>
|
||||
<ul className="top-buffer">
|
||||
<li>
|
||||
<h4>
|
||||
app.tsx: <small>header + page container.</small>
|
||||
</h4>
|
||||
</li>
|
||||
<li>
|
||||
<h4>
|
||||
header.tsx: <small>navigation links.</small>
|
||||
</h4>
|
||||
</li>
|
||||
<li>
|
||||
<h4>
|
||||
aboutPage.tsx / membersPage.tsx: <small>pages</small>
|
||||
</h4>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -1,8 +1,60 @@
|
|||
import * as React from 'react';
|
||||
// import { Segment } from 'semantic-ui-react';
|
||||
import { Form, Container, Input, TextArea, Button } from 'semantic-ui-react';
|
||||
|
||||
export const About: React.StatelessComponent<{}> = () => {
|
||||
return (
|
||||
null
|
||||
);
|
||||
export class AddPost extends React.Component<any, any> {
|
||||
constructor(props: any) {
|
||||
super(props);
|
||||
this.state = { title: 'Title', content: 'Some Content' };
|
||||
}
|
||||
public render() {
|
||||
let submitHandler = (e: any, d: any) => {
|
||||
let postContent = JSON.stringify(this.state);
|
||||
console.log('posting : ', postContent);
|
||||
fetch('/api/post', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: postContent,
|
||||
})
|
||||
.then((response) => {
|
||||
if (response.status === 200) {
|
||||
console.log('submitted successfully');
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log('some error occurred');
|
||||
});
|
||||
};
|
||||
return (
|
||||
<Container>
|
||||
<Form onSubmit={submitHandler}>
|
||||
<Form.Group widths="equal">
|
||||
<Form.Field
|
||||
id="form-input-control-first-name"
|
||||
control={Input}
|
||||
label="Title"
|
||||
placeholder="Give a title"
|
||||
onChange={(t: any, d: any) => this.setState({ title: d.value })}
|
||||
/>
|
||||
</Form.Group>
|
||||
<Form.Field
|
||||
id="form-textarea-control-opinion"
|
||||
control={TextArea}
|
||||
label="Content"
|
||||
placeholder="Write the paragraphs in the post here"
|
||||
onChange={(t: any, d: any) => this.setState({ content: d.value })}
|
||||
/>
|
||||
<Form.Field
|
||||
id="form-button-control-public"
|
||||
control={Button}
|
||||
content="Submit"
|
||||
label="Submit"
|
||||
|
||||
/>
|
||||
</Form>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,11 +7,11 @@ export const Header: React.StatelessComponent<{}> = () => {
|
|||
<nav className="navbar navbar-default">
|
||||
<div className="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
|
||||
<ul className="nav navbar-nav">
|
||||
<li><Link to="/about">About</Link></li>
|
||||
<li><Link to="/members">Members</Link></li>
|
||||
<li><Link to="/addpost">Add New Post</Link></li>
|
||||
<li><Link to="/listposts">List Posts</Link></li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,3 +1,2 @@
|
|||
export * from './header';
|
||||
export * from './about';
|
||||
export * from './members';
|
||||
export * from './addpost';
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
export * from './page';
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
import * as React from 'react';
|
||||
|
||||
export const MembersPage: React.StatelessComponent<{}> = () => {
|
||||
return (
|
||||
<div className="row">
|
||||
<h2> Members Page</h2>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -19,3 +19,5 @@
|
|||
background: #e7e7e7 !important;
|
||||
color: #333 !important;
|
||||
}
|
||||
|
||||
@import "~semantic-ui-css/semantic.min.css";
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import * as React from 'react';
|
||||
import * as ReactDOM from 'react-dom';
|
||||
import { AppRouter } from './router';
|
||||
import './css/site.css';
|
||||
|
||||
ReactDOM.render(
|
||||
<AppRouter />
|
||||
, document.getElementById('root'));
|
||||
ReactDOM.render(<AppRouter />, document.getElementById('root'));
|
||||
|
|
|
|||
|
|
@ -1,16 +1,16 @@
|
|||
import * as React from 'react';
|
||||
import { Route, HashRouter } from 'react-router-dom';
|
||||
import { App } from './app';
|
||||
import { About, MembersPage } from './components';
|
||||
import { AddPost } from './components';
|
||||
|
||||
export const AppRouter: React.StatelessComponent<{}> = () => {
|
||||
return (
|
||||
<HashRouter>
|
||||
<div >
|
||||
<Route exact={true} path="/" component={App} />
|
||||
<Route path="/about" component={About} />
|
||||
<Route path="/members" component={MembersPage} />
|
||||
<Route path="/addpost" component={AddPost} />
|
||||
<Route path="/listposts" component={AddPost} />
|
||||
</div>
|
||||
</HashRouter>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -29,12 +29,10 @@
|
|||
"static-before-instance",
|
||||
"variables-before-functions"
|
||||
],
|
||||
"no-any": true,
|
||||
"no-arg": true,
|
||||
"no-bitwise": true,
|
||||
"no-console": [
|
||||
true,
|
||||
"log",
|
||||
"error",
|
||||
"debug",
|
||||
"info",
|
||||
|
|
|
|||
10
yarn.lock
10
yarn.lock
|
|
@ -2810,6 +2810,10 @@ jest@20.0.3:
|
|||
dependencies:
|
||||
jest-cli "^20.0.3"
|
||||
|
||||
jquery@x.*:
|
||||
version "3.2.1"
|
||||
resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.2.1.tgz#5c4d9de652af6cd0a770154a631bba12b015c787"
|
||||
|
||||
js-base64@^2.1.9:
|
||||
version "2.1.9"
|
||||
resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.1.9.tgz#f0e80ae039a4bd654b5f281fc93f04a914a7fcce"
|
||||
|
|
@ -4617,6 +4621,12 @@ select-hose@^2.0.0:
|
|||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca"
|
||||
|
||||
semantic-ui-css@^2.2.12:
|
||||
version "2.2.12"
|
||||
resolved "https://registry.yarnpkg.com/semantic-ui-css/-/semantic-ui-css-2.2.12.tgz#afc462e5bb4f8a0dcfe3dca11274499a997490dd"
|
||||
dependencies:
|
||||
jquery x.*
|
||||
|
||||
semantic-ui-react@^0.71.3:
|
||||
version "0.71.3"
|
||||
resolved "https://registry.yarnpkg.com/semantic-ui-react/-/semantic-ui-react-0.71.3.tgz#3313ade18ad11db88efcf2cade42ce7fa5ed9fd6"
|
||||
|
|
|
|||
Loading…
Reference in New Issue