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.2k
ふんわり使うPlantUML
suzuki
0
970
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
650
Automatically run the JavaScript test in multiple browsers
suzuki
5
6.1k
Other Decks in Programming
See All in Programming
AWS IaCの注目アップデート 2024年10月版
konokenj
3
3.1k
プロジェクト新規参入者のリードタイム短縮の観点から見る、品質の高いコードとアーキテクチャを保つメリット
d_endo
1
1k
Why Spring Matters to Jakarta EE - and Vice Versa
ivargrimstad
0
970
Vue SFCのtemplateでTypeScriptの型を活用しよう
tsukkee
3
1.5k
Outline View in SwiftUI
1024jp
1
110
Golang と Erlang
taiyow
8
1.9k
詳細解説! ArrayListの仕組みと実装
yujisoftware
0
480
讓數據說話:用 Python、Prometheus 和 Grafana 講故事
eddie
0
350
カラム追加で増えるActiveRecordのメモリサイズ イメージできますか?
asayamakk
4
1.5k
レガシーな Android アプリのリアーキテクチャ戦略
oidy
1
170
Vaporモードを大規模サービスに最速導入して学びを共有する
kazukishimamoto
4
4.3k
gopls を改造したら開発生産性が高まった
satorunooshie
8
240
Featured
See All Featured
No one is an island. Learnings from fostering a developers community.
thoeni
19
3k
Designing Dashboards & Data Visualisations in Web Apps
destraynor
228
52k
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
126
18k
Build The Right Thing And Hit Your Dates
maggiecrowley
32
2.4k
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
31
2.7k
Raft: Consensus for Rubyists
vanstee
136
6.6k
Testing 201, or: Great Expectations
jmmastey
38
7k
Making the Leap to Tech Lead
cromwellryan
132
8.9k
Imperfection Machines: The Place of Print at Facebook
scottboms
264
13k
Optimising Largest Contentful Paint
csswizardry
33
2.9k
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
25
1.8k
Large-scale JavaScript Application Architecture
addyosmani
510
110k
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