Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
How to walk in the Crowi
Search
Norio Suzuki
November 03, 2016
Programming
6
15k
How to walk in the Crowi
How to walk in the Crowi / Crowi の歩き方
at PHP Conference 2016
http://phpcon.php.gr.jp/2016/
Norio Suzuki
November 03, 2016
Tweet
Share
More Decks by Norio Suzuki
See All by Norio Suzuki
リーダブル プルリクエスト 分割プルリクエスト編 / Readable Pull Request
suzuki
3
1.3k
ふんわり使うPlantUML
suzuki
0
1k
Symfony Serializer Deep Dive
suzuki
0
2k
Swift Mailer Update
suzuki
2
2.3k
Guzzle Promiseを使った 非同期処理によるAPIコールの高速化
suzuki
15
16k
PHP BLT #4
suzuki
1
4.6k
Learning Swift2 with PHP7
suzuki
2
4.1k
ポモドーロ・テクニック入門の入門
suzuki
0
660
Automatically run the JavaScript test in multiple browsers
suzuki
5
6.1k
Other Decks in Programming
See All in Programming
flutterkaigi_2024.pdf
kyoheig3
0
150
ローコードSaaSのUXを向上させるためのTypeScript
taro28
1
630
3rd party scriptでもReactを使いたい! Preact + Reactのハイブリッド開発
righttouch
PRO
1
610
シェーダーで魅せるMapLibreの動的ラスタータイル
satoshi7190
1
480
Realtime API 入門
riofujimon
0
150
最新TCAキャッチアップ
0si43
0
190
Jakarta EE meets AI
ivargrimstad
0
210
受け取る人から提供する人になるということ
little_rubyist
0
250
Macとオーディオ再生 2024/11/02
yusukeito
0
370
Amazon Qを使ってIaCを触ろう!
maruto
0
410
色々なIaCツールを実際に触って比較してみる
iriikeita
0
330
EMになってからチームの成果を最大化するために取り組んだこと/ Maximize team performance as EM
nashiusagi
0
100
Featured
See All Featured
StorybookのUI Testing Handbookを読んだ
zakiyama
27
5.3k
How to Ace a Technical Interview
jacobian
276
23k
Fantastic passwords and where to find them - at NoRuKo
philnash
50
2.9k
Embracing the Ebb and Flow
colly
84
4.5k
Designing for Performance
lara
604
68k
Designing Dashboards & Data Visualisations in Web Apps
destraynor
229
52k
How To Stay Up To Date on Web Technology
chriscoyier
788
250k
Product Roadmaps are Hard
iamctodd
PRO
49
11k
Visualizing Your Data: Incorporating Mongo into Loggly Infrastructure
mongodb
42
9.2k
The Cult of Friendly URLs
andyhume
78
6k
BBQ
matthewcrist
85
9.3k
Building Applications with DynamoDB
mza
90
6.1k
Transcript
How to walk in the Crowi ʙ How PHPer developed
the product of Node.js ʙ PHP Conference 2016 (Tokyo) 2016-11-03 @suzuki
Crowi ͷา͖ํ ʙPHPer ͕ Node.js ͷϓϩμΫτΛ৮ΔΑ͏ʹͳΔ·Ͱʙ PHP Conference 2016 (Tokyo)
2016-11-03 @suzuki
About me
Twitter: @suzuki GitHub: @suzuki
PHP Conference Fukuoka 2016 https://speakerdeck.com/suzuki/guzzle-promisewoshi-tuta-fei-tong-qi-chu-li-niyoruapikorufalsegao-su-hua
PHP Conference Kansai 2016 https://speakerdeck.com/suzuki/swift-mailer-update
Contributor of Crowi https://github.com/crowi/crowi/graphs/contributors
What is Crowi?
Crowi http://site.crowi.wiki/
Features ɾ Wiki ɾ Markdown ɾ Realtime preview ɾ Login
by Google Account ɾ Notification to Slack
GitHub: crowi/crowi https://github.com/crowi/crowi
More information https://medium.com/crowi-book
More information https://speakerdeck.com/sotarok/crowi
Why am I started to develop the Crowi?
When the year-end party in 2015
Talk about "esa.io" I like "esa.io". I love their Markdown
helper. OK. You create it. I want to use that helper on Crowi. esa logo : https://docs.esa.io/posts/125
He is product founder of Crowi https://github.com/crowi/crowi/graphs/contributors
I tried to implement
Pull request https://github.com/crowi/crowi/pull/38
Pull request https://github.com/crowi/crowi/pull/38
This is my opportunity to develop the Crowi
Crowi overview
System Diagram .POHP%# &MBTUJDTFBSDI 3FEJT "NB[PO4 4MBDL 3FRVJSF 0QUJPOBM Remote
Notification Full text search Data Store Session Data File upload <$SPXJ> /PEFKT (PPHMF Social Login
<$SPXJ> $MJFOU4JEF 4FSWFS4JEF Inside Crowi /PEFKT &YQSFTT .POHPPTF 4XJH #SPXTFS
K2VFSZ 3FBDU #PPUTUSBQ
How to develop?
Install and Configuration https://github.com/crowi/crowi/wiki/Install-and-Configuration
or
GitHub: suzuki/crowi-develop https://github.com/suzuki/crowi-develop
What is "crowi-develop" ɾ Setup Docker containers ɾMongoDB ɾRedis ɾElasticsearch
ɾ Require ɾNode.js ɾDocker for Mac
What is "suzuki/crowi-develop" .POHP%# &MBTUJDTFBSDI 3FEJT "NB[PO4 4MBDL 3FRVJSF 0QUJPOBM
<$SPXJ> /PEFKT (PPHMF Prepare these
How to initialize "crowi-develop"
Clone "crowi-develop" repository $ git clone https://github.com/suzuki/crowi-develop
Clone "crowi" repository $ cd crowi-develop $ git clone
[email protected]
:crowi/crowi.git
Files in "crowi-develop" LICENSE README.md crowi/ data/ docker-compose.yml Crowi directory
Data directory for Docker containers
Run Docker containers $ cd crowi-develop $ docker-compose up -d
Run Crowi $ cd crowi-develop/crowi $ PASSWORD_SEED=somesecretstring \ MONGO_URI=mongodb://localhost/crowi
\ ELASTICSEARCH_URI=localhost:9200 \ REDIS_URL=localhost \ FILE_UPLOAD=local \ node app.js Change your own word
Open localhost:3000 http://localhost:3000/
Create administrator http://localhost:3000/installer
Open administration menu http://localhost:3000/ Administration menu
Open search menu http://localhost:3000/admin Search menu
Build search index http://localhost:3000/admin/search Build index
Daily routine: start up "crowi-develop"
Run Docker container $ cd crowi-develop $ docker-compose up -d
Run Crowi $ cd crowi-develop/crowi $ PASSWORD_SEED=somesecretstring \ MONGO_URI=mongodb://localhost/crowi
\ ELASTICSEARCH_URI=localhost:9200 \ REDIS_URL=localhost \ FILE_UPLOAD=local \ node app.js Change your own word
Daily routine: shutdown "crowi-develop"
Shutdown Crowi $ PASSWORD_SEED=somesecretstring \ MONGO_URI=mongodb://localhost/crowi \ ELASTICSEARCH_URI=localhost:9200 \
REDIS_URL=localhost \ FILE_UPLOAD=local \ node app.js Press Ctrl + C
Shutdown Docker container $ docker-compose stop
Case study: I want to modify…
I want to modify CSS
<$SPXJ> $MJFOU4JEF 4FSWFS4JEF CSS /PEFKT &YQSFTT .POHPPTF 4XJH #SPXTFS K2VFSZ
3FBDU #PPUTUSBQ
Keywords of using tools ɾ Bootstrap ɾ Sass ɾ Gulp
Go to directory $ cd crowi/resource/css/
Modify files $ ls -1F _admin.scss _comment.scss _form.scss _layout.scss _mixins.scss
_page.scss _page_list.scss _portal.scss _search.scss _user.scss _utilities.scss _variables.scss _wiki.scss crowi-reveal.scss crowi.scss "_NAME.scss" are component "crowi.scss" is main file
Build $ ./node_modules/.bin/gulp css
Check result ɾ Reload your browser
Watch files $ ./node_modules/.bin/gulp watch
I want to modify HTML
<$SPXJ> $MJFOU4JEF 4FSWFS4JEF HTML (Template) /PEFKT &YQSFTT .POHPPTF 4XJH #SPXTFS
K2VFSZ 3FBDU #PPUTUSBQ
Keywords of using tools ɾ Swig
Swig: template engine https://www.npmjs.com/package/swig
Format sample <h1>{{ pagename }}</h1> <ul> {% for author in
authors %} <li>{{ author }}</li> {% endfor %} </ul> variable name for loop
Swig is similar to the Twig http://twig.sensiolabs.org/
Go to directory $ cd crowi/lib/views/
Modify files $ ls -1F 500.html _form.html admin/ index.html installer.html
invited.html layout/ login/ login.html mail/ me/ modal/ page.html page_list.html page_presentation.html search.html user/ user_page.html widget/ "*.html" are template of Swig
Build Nothing to do
Check result ɾ Restart Crowi ɾ Reload your browser
I want to modify Front-end JavaScript
<$SPXJ> $MJFOU4JEF 4FSWFS4JEF Front-end JavaScript /PEFKT &YQSFTT .POHPPTF 4XJH #SPXTFS
K2VFSZ 3FBDU #PPUTUSBQ
Keywords of using tools ɾ jQuery
Go to directory $ cd crowi/resource/js/
Modify files $ ls -1F app.js components/ crowi-admin.js crowi-form.js crowi-presentation.js
crowi.js util/
Build $ ./node_modules/.bin/gulp [dev]
I want to modify Front-end JavaScript (React)
<$SPXJ> $MJFOU4JEF 4FSWFS4JEF Front-end JavaScript (React) /PEFKT &YQSFTT .POHPPTF 4XJH
#SPXTFS K2VFSZ 3FBDU #PPUTUSBQ
Keywords of using tools ɾ Swig ɾ React
Our future plan: Use React more
Go to directory $ cd crowi/resource/js/
Modify files $ ls -1F app.js components/ crowi-admin.js crowi-form.js crowi-presentation.js
crowi.js util/ React components ReactDOM.render()
Modify files (components) $ ls -1F components/ HeaderSearchBox/ HeaderSearchBox.js Page/
PageList/ PageListSearch.js SearchPage/ SearchPage.js User/
Modify Template 4XJH5FNQMBUF EJWJE40.&@*%@'03@3&/%&3EJW React component will render here
Modify React renderer (in app.js) const componentMappings = { 'search-top':
<HeaderSearchBox />, 'search-page': <SearchPage />, 'page-list-search': <PageListSearch />, }; Object.keys(componentMappings).forEach((key) => { const elem = document.getElementById(key); if (elem) { ReactDOM.render(componentMappings[key], elem); } }); DOM id (in Swig template)
Similar case http://techlife.cookpad.com/entry/2016/10/26/135818
Build $ ./node_modules/.bin/gulp [dev]
Check result ɾ Restart Crowi ɾif you modified template ɾ
Reload your browser
I want to add Some New feature
<$SPXJ> $MJFOU4JEF 4FSWFS4JEF Some new feature (server side) /PEFKT &YQSFTT
.POHPPTF 4XJH #SPXTFS K2VFSZ 3FBDU #PPUTUSBQ
Keywords of using tools ɾ Express ɾ Mongoose ɾ Swig
MVC of Crowi .PEFM .POHPPTF 7JFX 4XJH 3FBDU $POUSPMMFS &YQSFTT
$POUSPMMFS .PEFM Request flow SPVUFTJOEFYKT SPVUFT3065&@KT NPEFMT.0%&-@KT Request NPEFMT.0%&-@KT NPEFMT.0%&-@OKT
SPVUFT3065&@KT SPVUFT3065&@OKT
Controller: Express
Express http://expressjs.com/
Go to directory $ cd crowi/lib/routes/
Modify files $ ls -1F admin.js attachment.js bookmark.js comment.js index.js
installer.js login.js logout.js me.js page.js revision.js search.js user.js
Router: index.js
Router (index.js) var page = require('./page')(crowi, app); var middleware =
require('../util/middlewares'); var loginRequired = middleware.loginRequired; app.get('/*/$', loginRequired(crowi, app), page.pageListShow); app.get('/*', loginRequired(crowi, app), page.pageShow); HTTP method Request path Router (Controller) method
page.pageShow (page.js) actions.pageShow = function(req, res) { var path =
path || getPathFromRequest(req); Page.findPage(path, req.user, req.query.revision) .then(function(page) { // some routines return renderPage(page, req, res); }).catch(function(err) { // not found }); }; Page model method
Model: Mongoose
Mongoose http://mongoosejs.com/
Go to directory $ cd crowi/lib/models/
Modify files $ ls -1F attachment.js bookmark.js comment.js config.js index.js
page.js revision.js updatePost.js user.js
DB Schema (page.js) pageSchema = new mongoose.Schema({ path: {type: String,
required: true, index: true, unique: true}, revision: {type: ObjectId, ref: 'Revision'}, status: {type: String, default: STATUS_PUBLISHED, index: true}, creator: {type: ObjectId, ref: 'User', index: true}, createdAt: {type: Date, default: Date.now}, }
Sample Data
Sample page Page + Revision data
"path" field: String pageSchema = new mongoose.Schema({ path: {type: String,
required: true, index: true, unique: true}, revision: {type: ObjectId, ref: 'Revision'}, status: {type: String, default: STATUS_PUBLISHED, index: true}, creator: {type: ObjectId, ref: 'User', index: true}, createdAt: {type: Date, default: Date.now}, } type: String
"path" field data { "_id": ObjectId("580fe42645419f6dcf5f4c49"), "path": "/user/suzuki/memo/2016/10/26/test_page", "revision": ObjectId("580fe42645419f6dcf5f4c4a")
"status": "published", "creator": ObjectId("580401458462d38221a37094"), "createdAt": ISODate("2016-10-25T23:00:54.020Z"), } String data
"revision" field: ObjectId pageSchema = new mongoose.Schema({ path: {type: String,
required: true, index: true, unique: true}, revision: {type: ObjectId, ref: 'Revision'}, status: {type: String, default: STATUS_PUBLISHED, index: true}, creator: {type: ObjectId, ref: 'User', index: true}, createdAt: {type: Date, default: Date.now}, } type: ObjectId ref: 'Revision'
"revision" field data { "_id": ObjectId("580fe42645419f6dcf5f4c49"), "path": "/user/suzuki/memo/2016/10/26/test_page", "revision": ObjectId("580fe42645419f6dcf5f4c4a")
"status": "published", "creator": ObjectId("580401458462d38221a37094"), "createdAt": ISODate("2016-10-25T23:00:54.020Z"), } This means reference 'Revision'
Revision data { "_id": ObjectId("580fe42645419f6dcf5f4c4a"), "author": ObjectId("580401458462d38221a37094"), "body": "# test_page\r\n\r\nThis
is a test page.\r\n", "path": "/user/suzuki/memo/2016/10/26/test_page", }
Schema types of Mongoose ɾ String ɾ Number ɾ Date
ɾ Buffer ɾ Boolean ɾ Mixed ɾ ObjectId ɾ Array MongoDB is schema-less, But, Mongoose has schema types
Method (page.js) // find page and check if granted user
pageSchema.statics.findPage = function(path, userData, revisionId, ignoreNotFound) { var self = this; return new Promise(function(resolve, reject) { self.findOne({path: path}, function(err, pageData) { if (err) { return reject(err); } if (pageData === null) { if (ignoreNotFound) { return resolve(null); } var pageNotFoundError = new Error('Page Not Found') pageNotFoundError.name = 'Crowi:Page:NotFound'; return reject(pageNotFoundError); } // snip
View: Swig + React
See CSS, Front-end JS page
How to debug
Debug log
var debug = require('debug')('crowi:routes:page'); Define debug (routes/page.js) Key name
actions.pageListShow = function(req, res) { var path = getPathFromRequest(req); debug('Page
list show', path); Call debug (routes/page.js) No output by default
Run Crowi with DEBUG environment $ PASSWORD_SEED=somesecretstring \ MONGO_URI=mongodb://localhost/crowi
\ ELASTICSEARCH_URI=localhost:9200 \ REDIS_URL=localhost \ FILE_UPLOAD=local \ DEBUG=crowi:routes:page \ node app.js Set DEBUG env.
Run Crowi with DEBUG environment [development] Express server listening on
port 3000 crowi:routes:page Page list show +0ms / Debug log
lib/routes/page.js: var debug = require('debug')('crowi:routes:page'); lib/routes/revision.js: var debug = require('debug')('crowi:routes:revision');
lib/models/page.js: var debug = require('debug')('crowi:models:page'); lib/models/comment.js: var debug = require('debug')('crowi:models:comment'); Wildcard DEBUG env. DEBUG=crowi:models:*
More information about DEBUG ɾ Debugging Express ɾ http://expressjs.com/en/guide/debugging.html (English)
ɾ http://expressjs.com/ja/guide/debugging.html (Japanese)
View data
Get container name MondoDB container name is here. For this
example, "crowidevelop_mongodb_1"
Login container $ docker exec -it crowidevelop_mongodb_1 /bin/bash Execute "/bin/bash"
in container
Run mongo CLI root@f7e7c8334c37:/# mongo MongoDB shell version: 3.2.9 connecting
to: local >
Select database > use crowi switched to db crowi
Show collections (SHOW TABLES) > show collections attachments bookmarks comments
configs pages revisions updateposts users Collections are mapped to Models
Find data (SELECT data) > db.pages.find(); SELECT * FROM pages;
Find data: WHERE Clause > db.pages.find({"_id": ObjectId("580fe42645419f6dcf5f4c49")}); SELECT * FROM
pages WHERE _id = ObjectId("580fe42645419f6dcf5f4c49")
find() > db.pages.find(); { "_id" : ObjectId("580fe42645419f6dcf5f4c49"), "redirectTo" : null,
"updatedAt" : ISODate("2016-10-25T23:00:54.091Z"), "lastUpdateUser" : ObjectId("580401458462d38221a37094"), "creator" : ObjectId("580401458462d38221a37094"), "path" : "/ user/suzuki/memo/2016/10/26/test_page", "createdAt" : ISODate("2016-10-25T23:00:54.020Z"), "extended" : "{}", "commentCount" : 1, "seenUsers" : [ ObjectId("580401458462d38221a37094") ], "liker" : [ ], "grantedUsers" : [ ObjectId("580401458462d38221a37094") ], "grant" : 1, "status" : "published", "__v" : 1, "revision" : ObjectId("580fe42645419f6dcf5f4c4a") }
find().pretty() > db.pages.find().pretty(); { "_id" : ObjectId("580fe42645419f6dcf5f4c49"), "redirectTo" : null,
"updatedAt" : ISODate("2016-10-25T23:00:54.091Z"), "lastUpdateUser" : ObjectId("580401458462d38221a37094"), "creator" : ObjectId("580401458462d38221a37094"), "path" : "/user/suzuki/memo/2016/10/26/test_page", "createdAt" : ISODate("2016-10-25T23:00:54.020Z"), "extended" : "{}", "commentCount" : 1, // snip "status" : "published", "revision" : ObjectId("580fe42645419f6dcf5f4c4a") }
More information about MongoDB ɾ The mongo Shell ɾ https://docs.mongodb.com/v3.2/mongo/
ɾ GUI ɾ https://docs.mongodb.com/ecosystem/tools/administration-interfaces/
How to Test?
Run tests $ ./node_modules/.bin/gulp test OR $ MONGO_URI=localhost:crowi_test \ ./node_modules/.bin/gulp
test "crowi_test" DB is used "crowi" (default) DB is used I recommend to use different name from "crowi"
Files $ cd crowi/tests/ $ ls -1F bootstrap.js crowi/ models/
util/ utils.js
Problems ɾ Coverage ɾ We have little tests... ɾ No
View test ɾ React component tests? ɾ E2E tests?
Conclusion
Crowi is a growing software ɾ Crowi is very simple
and useful ɾ Growing software ɾ We are using the Crowi in our company ɾ When received feedback, we will fixed that problem or create new features ɾ Try to use the Crowi in your organization
We learned first-step to develop Crowi ɾ Today, we have
learned how to develop the Crowi ɾ You can use your experience in PHP ɾ It is not difficult to develop
Today's theme http://phpcon.php.gr.jp/2016/
Next Action: Contribute! ɾ Code for Crowi ɾ Pull Request,
Issue, Document, etc. ɾ Talk about Crowi ɾ Gitter, Twitter, Facebook, Blog, etc. ɾ #crowi in Twitter ɾ Gitter: https://gitter.im/crowi/general
And, we are hiring! https://www.mercari.com/jp/jobs/ But, a full-time Crowi job
is not exist
Thank you
Appendix
Appendix ɾ Crowi ɾ https://github.com/crowi/crowi ɾ Crowi develop ɾ https://github.com/suzuki/crowi-develop
ɾ Crowi book (blog) ɾ https://medium.com/crowi-book ɾ Crowi gitter ɾ https://gitter.im/crowi/general