675 Commits
Author SHA1 Message Date
tmshv f52641b739 sync Page manifest refactoring 2020-03-10 17:51:21 +03:00
tmshv 955dcfb0ad sync delete fix 2020-03-10 17:41:16 +03:00
tmshv 112496fd1e sync utils io module to front_matter 2020-03-10 17:24:11 +03:00
tmshv 6a5dffe567 sync Page refactoring 2020-03-10 17:14:33 +03:00
tmshv 7bf49680cf Sync refactoring: split model to model + controller 2020-03-09 23:37:32 +03:00
tmshv 96040267bb v6.10.0 2020-03-05 20:48:35 +03:00
tmshv ad3eccfd7c dark theme 2020-03-05 20:47:57 +03:00
tmshv 58739a6b32 css variables cleanup 2020-03-05 19:40:53 +03:00
tmshv 1e3ceb5017 document shadow refactoring 2020-03-05 19:35:05 +03:00
tmshv f72e45bc46 color variables refactoring 2020-03-05 19:32:29 +03:00
tmshv b22d3fd19f fix missing color back var 2020-03-05 19:30:39 +03:00
tmshv 04d76d5961 style color variables refactoring and fixes 2020-03-05 17:56:53 +03:00
tmshv 7c939b5334 kazimir radius changed to 10px 2020-03-05 01:21:15 +03:00
tmshv ba1700d8ab v6.9.0 2020-03-05 00:27:51 +03:00
tmshv bc1a38043a Merge pull request #40 from tmshv/fix/article-layout-update
Article layout update
2020-03-05 00:26:43 +03:00
tmshv a4999dad9e css variables refactoring 2020-03-04 22:49:24 +03:00
tmshv 19f2535a24 styles updated; unused removed 2020-03-04 21:30:58 +03:00
tmshv 830a193333 article update 2020-03-04 15:41:28 +03:00
tmshv bf007b583c page layout upd 2020-03-04 15:41:01 +03:00
tmshv fa8b77252d initial article update: scss to css; minor refactoring 2020-03-04 15:25:13 +03:00
tmshv 21798f6821 marker table moved to css 2020-03-04 13:45:31 +03:00
tmshv 0d76cc156e v6.8.0 2020-03-04 01:09:38 +03:00
tmshv 8741986bb2 Merge pull request #39 from tmshv/fix/page-update
Page update
2020-03-04 01:08:32 +03:00
tmshv 1767b65856 PageMeta and TagList mobile layout fix 2020-03-03 21:56:56 +03:00
tmshv faf9ee0f7c Image load state styles disabled 2020-03-03 21:24:25 +03:00
tmshv b0b3f98233 PageGrid chunks; Image lazy removed (unstable in Safari) 2020-03-03 21:12:29 +03:00
tmshv 23b4b35395 src/utils removed 2020-03-03 19:07:27 +03:00
tmshv 729e09d061 src/lib cleanup 2020-03-03 19:07:12 +03:00
tmshv 6e110e3dd7 page grid image fixes 2020-03-03 08:08:55 +03:00
tmshv e800de1f92 page grid update: load less data 2020-03-03 07:53:16 +03:00
tmshv 1318328fe7 api page coverSrc support; filter tags response by field 2020-03-03 07:43:30 +03:00
tmshv 11ff066e6c Image component lazy behavior 2020-03-03 06:49:18 +03:00
tmshv 8f54454d32 PageGrid refactoring 2020-03-03 06:04:25 +03:00
tmshv a14db0e8da collective page images refactoring 2020-03-03 05:58:35 +03:00
tmshv 087a4b6172 index page update; rest module 2020-03-03 05:26:02 +03:00
tmshv 5e8ee6eec9 showAuthor defaults 2020-03-03 05:25:15 +03:00
tmshv a15f030956 sync rm unused get_id function 2020-03-03 05:24:53 +03:00
tmshv 09b41182ce PageMeta update text 2020-03-03 04:01:11 +03:00
tmshv 9fb6eaab66 dateFormat fix 2020-03-03 04:00:59 +03:00
tmshv 0b230a26b4 feed generator updated to tags 2020-03-03 03:05:34 +03:00
tmshv 79a127636c drop articles from sitemap 2020-03-03 03:05:18 +03:00
tmshv 44973faea3 PageMeta stability improve 2020-03-03 03:05:05 +03:00
tmshv 23835c27c9 moment -> date-fns 2020-03-03 02:51:14 +03:00
tmshv 6760f36177 page fix 2020-03-03 02:38:22 +03:00
tmshv 970bdce53d index page updated; ArticleGrid -> PageGrid 2020-03-03 02:31:42 +03:00
tmshv 85d2f7cc45 drop articles pages 2020-03-03 02:31:07 +03:00
tmshv 9a105ba45e page update 2020-03-03 02:25:37 +03:00
tmshv ee5cba3634 drop Article component 2020-03-03 02:24:24 +03:00
tmshv b680cba50c drop article page 2020-03-03 02:24:10 +03:00
tmshv 5610e50863 sync drop dead code 2020-03-03 02:22:33 +03:00
tmshv 92b64808ea sync Page logger warning add 2020-03-03 02:01:17 +03:00
tmshv 6b6eca5f8d sync drop Article model 2020-03-03 02:00:53 +03:00
tmshv 9eb087bf6d api tags controller simplified: rm tags/slug route 2020-03-03 01:35:36 +03:00
tmshv 06745b45f4 api drop unused code 2020-03-03 01:33:17 +03:00
tmshv d859fdb302 api pages by tags sorting key 2020-03-02 05:08:09 +03:00
tmshv 348c3baba8 api Page updated: refactor to make it looks like article 2020-03-02 04:40:01 +03:00
tmshv 68b7f4225d api Page update 2020-03-02 00:36:22 +03:00
tmshv af7f32b1c0 rm documents-container style 2020-02-29 02:03:25 +03:00
tmshv 286d5c4383 Merge pull request #38 from tmshv/fix/drop-schedules
drop schedule from app
2020-02-29 02:02:35 +03:00
tmshv 3fa1763913 drop schedule from app 2020-02-29 01:57:43 +03:00
tmshv 46009ef8f4 v6.7.0 2020-02-29 01:26:46 +03:00
tmshv 42857974e1 Merge pull request #37 from tmshv/fix/drop-documents-page
Drop documents page
2020-02-29 01:25:39 +03:00
tmshv de20ed726f sync cleanup 2020-02-29 01:19:04 +03:00
tmshv 263f18a1df drop documents page (now it is a regular page) 2020-02-29 01:04:28 +03:00
tmshv 55f44fab8c include tokens in result data 2020-02-29 01:03:42 +03:00
tmshv 1b5fc82e59 Token compile refactored 2020-02-29 01:03:18 +03:00
tmshv ec3e09b509 fix Page imports 2020-02-29 01:02:20 +03:00
tmshv 092fa4578b move create_post_from_image_list to Article (usage only there) 2020-02-29 01:02:04 +03:00
tmshv a2a73034da Document model pdf title stability improved (drop 0 byte from title value) 2020-02-29 00:58:58 +03:00
tmshv abbb977b8e rm unused from sync io lib 2020-02-29 00:58:24 +03:00
tmshv dcea20b046 rm SyncDocuments (now it in the page only) 2020-02-29 00:58:12 +03:00
tmshv 71f4ca8a2c rm unused functions from Marker 2020-02-29 00:57:08 +03:00
tmshv 95925cffe5 rm DocumentUrlToken and MarkerRun 2020-02-29 00:56:33 +03:00
tmshv 5d56d308b5 remove kazimir code moved to marker in the past 2020-02-29 00:56:09 +03:00
tmshv 58c317cc61 artlebedev typograph fallback for big pages 2020-02-29 00:53:43 +03:00
tmshv b9277795cf Merge pull request #36 from tmshv/fix/card-and-article-updates
Card and article updates
2020-02-28 11:33:41 +03:00
tmshv 2ae7572e7e drop fotorama dependencies 2020-02-28 11:29:24 +03:00
tmshv 7b83b03b09 sync settings update 2020-02-28 11:29:04 +03:00
tmshv 2774e05bc7 sync Image token is not joinable (drop fotorama support for a while) 2020-02-28 11:28:53 +03:00
tmshv 1544fae988 api article featured field 2020-02-28 11:28:25 +03:00
tmshv d5390fa99a ArticleGrid default image size changed 2020-02-27 21:10:54 +03:00
tmshv 0a470e2441 Merge pull request #35 from tmshv/fix/sync-cleanup
Sync cleanup
2020-02-27 21:06:09 +03:00
tmshv 33dffa099e sync readme usage section edited 2020-02-27 21:02:17 +03:00
tmshv d1fc26fcf3 rm schedule, settings and other from sync 2020-02-27 17:51:21 +03:00
tmshv 14a5804991 add collective image to app server 2020-02-27 17:42:44 +03:00
tmshv 61e3b615a8 Merge pull request #34 from tmshv/fix/default-page-image
Default page image
2020-02-27 17:40:05 +03:00
tmshv a16c05968a APP_CARD_DEFAULT_IMAGE changed 2020-02-27 17:31:50 +03:00
tmshv 9975754aa7 api page factory fixed 2020-02-27 17:29:06 +03:00
tmshv 3b532f1f50 api page factory improved 2020-02-27 17:24:59 +03:00
tmshv f08d577e11 ArticleGrid img 2020-02-27 17:12:15 +03:00
tmshv b96e06068e Merge branch 'master' into fix/default-page-image 2020-02-27 16:25:12 +03:00
tmshv 28ca79a19a rm unused ImageArtifactType 2020-02-27 16:24:52 +03:00
tmshv 58b5eac61e document page cleaned from debug 2020-02-27 16:24:35 +03:00
tmshv 1e44a22c0c ArticleList removed: use ArticleGrid instead 2020-02-27 16:24:06 +03:00
tmshv a01888f155 comments removed 2020-02-27 16:23:49 +03:00
tmshv 97fec50d48 hudozka main image moved to static: now it will be served from app server 2020-02-27 16:22:39 +03:00
tmshv c8fd2907ca ArticleGrid no preview fallback (wip) 2020-02-27 16:21:42 +03:00
tmshv f540f5be06 api article factory fixed 2020-02-27 16:13:10 +03:00
tmshv 96328a1236 api doesnt work with default page image 2020-02-27 15:57:14 +03:00
tmshv 193e8e3ca2 v6.6.0 2020-02-27 12:30:14 +03:00
tmshv 38f6d5b62f Merge pull request #33 from tmshv/fix/drop-albums
Drop albums
2020-02-27 11:29:44 +03:00
tmshv cc2580aedb drop album support from api 2020-02-27 11:25:17 +03:00
tmshv 8b810d7817 drop album support from sync 2020-02-27 11:24:54 +03:00
tmshv f993b4e5b5 drop album support from app 2020-02-27 11:24:19 +03:00
tmshv a738ef0f6b v6.5.0 2020-02-25 18:31:49 +03:00
tmshv d7d582fe5b add modules to ts exclude 2020-02-25 18:30:49 +03:00
tmshv c943ffc814 articles pages size changed to 24 2020-02-25 18:30:31 +03:00
tmshv 9bdfe8faec rm unused assets 2020-02-25 18:30:05 +03:00
tmshv 3d59757c28 Merge pull request #32 from tmshv/fix/drop-person-entity
Drop person entity
2020-02-25 04:51:44 +03:00
tmshv b9211e1ea3 rm schedule from menu 2020-02-25 04:39:03 +03:00
tmshv 893b5b9ccd rm teachers from sitemap (now they in pages) 2020-02-25 04:36:19 +03:00
tmshv fdac9d9ff8 api cleaned up from person/teacher model at all 2020-02-25 04:35:05 +03:00
tmshv ebd6290ccf remove Person model from sync as it never exist 2020-02-25 04:11:23 +03:00
tmshv 4c0e968e5e rm person page cause now its common page 2020-02-25 03:54:24 +03:00
tmshv 9cf7de825a collective page: display common page cards instead of person card 2020-02-25 03:53:58 +03:00
tmshv a3644c721b Merge pull request #31 from tmshv/fix/api-image-file
api image by file fixed
2020-02-25 03:52:43 +03:00
tmshv 1d9495f5f4 api image by file fixed 2020-02-25 03:52:21 +03:00
tmshv 6ba74ca911 Merge pull request #30 from tmshv/fix/api-page-and-article-updated
api updates
2020-02-25 02:37:32 +03:00
tmshv 0b3194a281 api updates 2020-02-25 02:37:05 +03:00
tmshv ad2c0367d0 Merge pull request #29 from tmshv/fix/opengraph-update
OpenGraph update
2020-02-25 02:32:02 +03:00
tmshv b62a0588ae wildcard page meta stability improved 2020-02-25 02:28:31 +03:00
tmshv 488ea6ec06 article related pages meta update and other improvements 2020-02-25 02:01:57 +03:00
tmshv 9e5ec860e8 article cleanup + small changes 2020-02-25 01:19:36 +03:00
tmshv 21a89c7d66 article page input data refactoring 2020-02-25 00:14:00 +03:00
tmshv 66b26bc778 Page type updated 2020-02-24 23:41:43 +03:00
tmshv f8e2e9fc32 meta imports optimisation 2020-02-24 23:41:28 +03:00
tmshv 6aaeb7e048 wildcard page description default to null 2020-02-24 23:40:50 +03:00
tmshv e7de465e2c wildcard page meta updated 2020-02-24 20:09:56 +03:00
tmshv 76e7a7e9bb collective page card style changed; pass common card data to grid 2020-02-24 02:29:15 +03:00
tmshv cdeece2b0b person page cleanup 2020-02-24 02:27:52 +03:00
tmshv b8d0c7aa91 added person and image related types 2020-02-24 02:27:28 +03:00
tmshv dbf09f608a meta builder; person page refactoring 2020-02-24 00:30:58 +03:00
tmshv 3f8941b613 person page rm debugging code 2020-02-24 00:28:52 +03:00
tmshv 88d5a56fec teacher page uses meta builder 2020-02-23 22:55:06 +03:00
tmshv 0fc762c418 meta lib refactoring: to ts; add meta builder 2020-02-23 22:54:43 +03:00
tmshv 8c57c69583 Meta component changes in definition 2020-02-23 22:54:15 +03:00
tmshv c4bf06f10a Merge pull request #28 from tmshv/fix/move-sync-to-modules
Move sync to modules
2020-02-23 21:43:59 +03:00
tmshv 13b761a81e sync moved to modules 2020-02-23 21:25:17 +03:00
tmshv 1dda6ce8cc v6.4.0 2020-02-23 21:21:13 +03:00
tmshv 2eaeb57241 Merge pull request #27 from tmshv/fix/font-optimisation
Font optimisation
2020-02-23 21:20:08 +03:00
tmshv 6c052d897b google fonts moved to css import; unused font removed 2020-02-23 20:21:09 +03:00
tmshv 20c81874fd Merge branch 'master' of github.com:tmshv/hudozka 2020-02-23 08:00:25 +03:00
tmshv 5375165d9b Merge pull request #24 from tmshv/fix/menu-refactoring
New menu
2020-02-23 07:59:56 +03:00
tmshv 123eb9e2d9 Breadcrumbs delimiters alignment improved 2020-02-23 07:51:02 +03:00
tmshv 53a3e04913 hover menu icons removed 2020-02-23 07:43:58 +03:00
tmshv 79658002d5 menu with toggle updated; even icons changed 2020-02-23 07:43:26 +03:00
tmshv 1181bd61fd menu layout style fixed; margin bottom moved to outer component 2020-02-23 06:07:36 +03:00
tmshv 37bb74ac51 content size on mobile changed 2020-02-23 05:50:46 +03:00
tmshv 3bdb69c972 App imports cleanup 2020-02-23 05:50:22 +03:00
tmshv 6825751c08 App layout update 2020-02-23 05:50:15 +03:00
tmshv 471d8f4714 useScreenType replaced with useMobile; hide breadcrumbs on mobile 2020-02-23 05:49:52 +03:00
tmshv 822f1a0535 MenuIterm selected but clicable mode added 2020-02-23 05:10:01 +03:00
tmshv 74f785134f breadcrumb container layout got some beauties 2020-02-23 04:40:52 +03:00
tmshv aefa0ae2d4 fetch breadcrumbs from api; button disabled support; component fix 2020-02-23 04:29:26 +03:00
tmshv cd0ef0d316 api dockerignore updated 2020-02-23 03:51:29 +03:00
tmshv b2493a6ab2 Merge pull request #26 from tmshv/fix/api-pages-breadcrumbs
API pages breadcrumbs
2020-02-23 03:50:56 +03:00
tmshv f35f628aed get breadcrumbs moved to separate controller 2020-02-23 03:50:22 +03:00
tmshv 95caa3bac5 get breadcrumbs implemented 2020-02-23 03:48:45 +03:00
tmshv ebaebec835 initial breadcrumb builder 2020-02-23 03:43:46 +03:00
tmshv 113fb9db77 add express typings 2020-02-23 03:22:38 +03:00
tmshv 4c6d089b78 Merge pull request #25 from tmshv/fix/api-tags
Tags API
2020-02-23 03:14:26 +03:00
tmshv df7169a6d2 api port type is string 2020-02-23 03:13:09 +03:00
tmshv ec2609e900 initial tags api 2020-02-23 03:12:06 +03:00
tmshv 26c03dfbbf button EOL 2020-02-23 03:10:26 +03:00
tmshv db485056e0 added optional breadcrumbs; page layout refactoring; other chages 2020-02-23 02:31:05 +03:00
tmshv 1dbbe04d59 menu moved to config and context 2020-02-22 04:53:22 +03:00
tmshv e8fb2e817b menu style update 2020-02-22 04:37:33 +03:00
tmshv 57b6e249ea menu style cleanup 2020-02-22 04:22:26 +03:00
tmshv b07def3eee menu refactoring 2020-02-22 04:22:19 +03:00
tmshv 8a41a895fb text colors changed 2020-02-22 03:40:22 +03:00
tmshv be9f07bdb7 Menu component updated 2020-02-22 03:40:14 +03:00
tmshv 11d628fd50 article grid missing home page fix 2020-02-22 03:28:04 +03:00
tmshv 2fa0083fd1 v6.3.0 2020-02-22 03:15:16 +03:00
tmshv e09574586a Merge pull request #23 from tmshv/fix/new-cards
New cards
2020-02-22 03:13:51 +03:00
tmshv 70e8bd6460 content layout updated to improve mobile 2020-02-22 02:54:50 +03:00
tmshv 86c7c63c6c article grid featured simplified 2020-02-22 02:43:02 +03:00
tmshv 692f50ede4 CardGrid auto flow improved 2020-02-22 02:09:22 +03:00
tmshv 4ed68b235a article layout fix 2020-02-22 01:36:17 +03:00
tmshv 5c7ab73e68 article style cleanup 2020-02-22 01:36:06 +03:00
tmshv e66dfddeb9 card grid style cleanup 2020-02-22 01:35:55 +03:00
tmshv 89203b2b12 article grid updated 2020-02-22 01:35:43 +03:00
tmshv 5730505fca article, person cards removed; use common component 2020-02-22 00:42:55 +03:00
tmshv 13c7d473b1 add Card component 2020-02-22 00:08:31 +03:00
tmshv 0ce8486d99 Merge pull request #22 from tmshv/fix/content-simplify
Content simplify
2020-02-21 22:39:36 +03:00
tmshv 8f01c6e9d2 documents page rest fix 2020-02-21 22:26:26 +03:00
tmshv a28f7ccd84 fix api requests 2020-02-21 22:23:09 +03:00
tmshv 114bb8d9d4 footer-links scss rm 2020-02-21 22:11:58 +03:00
tmshv 97b6a4f192 album scss rm 2020-02-21 22:11:49 +03:00
tmshv eeccb97440 pages content layout fix 2020-02-21 22:10:37 +03:00
tmshv 85af28ac50 content moved to css 2020-02-21 21:56:50 +03:00
tmshv 400a08d1af content style update; style refactoring 2020-02-21 21:55:15 +03:00
tmshv 1bdea85b1b content style update: rm thin; rm menu padding 2020-02-21 21:33:49 +03:00
tmshv f2b548aee8 publicated 2020-02-21 20:32:13 +03:00
tmshv bed0548909 article style update 2020-02-21 20:16:23 +03:00
tmshv 7656f44b0b Merge pull request #21 from tmshv/fix/article-component-update
Article component update
2020-02-21 04:47:21 +03:00
tmshv 28483190e2 IArticle type fix 2020-02-21 04:34:11 +03:00
tmshv 0e482ad73c fix Article import 2020-02-21 04:30:38 +03:00
tmshv 65507c5d80 article tags refactoring 2020-02-21 04:26:48 +03:00
tmshv e7f3b0d7ce move to ts 2020-02-21 04:10:14 +03:00
tmshv 150404ca0b Merge pull request #20 from tmshv/fix/kazimir-style-update
Kazimir style update
2020-02-21 01:56:33 +03:00
tmshv f01ba79977 kazimir mobile style updated 2020-02-20 19:42:21 +03:00
tmshv d787789391 kazimir video update 2020-02-20 19:40:00 +03:00
tmshv 10cf899fe5 kazimir image style update 2020-02-20 19:39:49 +03:00
tmshv cc693228c6 article line height changed 2020-02-20 19:39:38 +03:00
tmshv a1a1ec20cc text css vars updated 2020-02-20 19:24:34 +03:00
tmshv 023ef5a348 article p margin removed 2020-02-20 19:24:16 +03:00
tmshv 25d49ed5b7 kazimir style updated 2020-02-20 19:24:08 +03:00
tmshv d144eb9cb5 kazimir styles -> to css 2020-02-20 19:07:23 +03:00
tmshv 3dbc1e6098 upd to v6.2.0 2020-02-20 17:31:24 +03:00
tmshv 19aa1f415e nextjs versiton updated to 6.2.2 stable 2020-02-20 17:30:02 +03:00
tmshv 59bd11acdc Merge pull request #19 from tmshv/fix/page-collective-update
Collective page update
2020-02-20 17:25:28 +03:00
tmshv 1ead6c44a0 person card style clean 2020-02-20 17:19:45 +03:00
tmshv 4d0fb7a8f6 collective page update: border radius, css refactoring 2020-02-20 17:17:22 +03:00
tmshv 3a425c25fe CardList removed 2020-02-20 17:16:04 +03:00
tmshv c317d6631f collective page uses card grid 2020-02-20 17:15:50 +03:00
tmshv 9b8b3d73c5 Contacts fix 2020-02-19 00:01:14 +03:00
tmshv 07cb773c6f collective page fix 2020-02-19 00:01:06 +03:00
tmshv 29c2a53c54 Merge pull request #18 from tmshv/fix/pager-update
New Pager
2020-02-18 23:59:23 +03:00
tmshv 5cf2dbf8f7 article cards updated 2020-02-18 23:49:24 +03:00
tmshv 168ebb81ce article page size is 12 2020-02-18 23:48:28 +03:00
tmshv 93d9021ac0 article card uses next link 2020-02-18 20:35:16 +03:00
tmshv 0b47b12d27 article card style updated 2020-02-18 20:33:30 +03:00
tmshv b46bc1234c effect css vars changed 2020-02-18 20:33:13 +03:00
tmshv 3631216be4 article card list updated 2020-02-18 20:31:07 +03:00
tmshv 55b4ce14d3 Pager updated 2020-02-18 19:49:46 +03:00
tmshv 41467aa447 add Button component; pager updated 2020-02-18 17:43:37 +03:00
tmshv 843ade58ad disable visited link 2020-02-18 17:42:55 +03:00
tmshv 4bf3b55557 pager styles jsx to css 2020-02-18 17:12:22 +03:00
tmshv 0ba0d74ea7 pager uses next link 2020-02-18 17:10:53 +03:00
tmshv 406c660f41 pager update 2020-02-18 17:09:21 +03:00
tmshv 5a3fc93c4f Merge pull request #17 from tmshv/fix/footer-refactoring
Footer refactoring
2020-02-18 16:25:09 +03:00
tmshv 88226e0038 not found component style update 2020-02-18 16:22:21 +03:00
tmshv 4881ca1aae style size variables 2020-02-18 16:22:13 +03:00
tmshv 8ea5e74232 opposite link fix 2020-02-18 16:14:39 +03:00
tmshv a668a8e602 theme refactoring; footer style refactoring 2020-02-18 16:13:39 +03:00
tmshv 8ed1e65055 block style refactoring 2020-02-18 15:49:12 +03:00
tmshv 2856afd263 footer style moved to css 2020-02-18 15:37:03 +03:00
tmshv 48f7e971c9 footer / block / contacts refactoring 2020-02-18 15:36:20 +03:00
tmshv d0a11deae8 Spacer typings improved; moved to separate component 2020-02-18 14:57:17 +03:00
tmshv 01eaffaf14 add Block component; copyright refactoring 2020-02-18 14:53:36 +03:00
tmshv 19b54c56e4 footer-info selector removed 2020-02-18 14:34:43 +03:00
tmshv add6b15265 Author component extraction 2020-02-18 14:32:50 +03:00
tmshv 5b19a6a359 Copyright component extraction 2020-02-18 14:31:27 +03:00
tmshv c0dd5cf6ae move footer props to config 2020-02-18 14:26:09 +03:00
tmshv 4f0d61735f Merge pull request #16 from tmshv/fix/clean-old-styles
Remove old styles
2020-02-18 13:01:17 +03:00
tmshv de63b5e778 App.Header refactoring 2020-02-18 12:29:21 +03:00
tmshv 5cc0aa1c0b Merge branch 'master' into fix/clean-old-styles 2020-02-18 12:23:29 +03:00
tmshv 2511f431c4 navigation style cleanup 2020-02-18 12:19:59 +03:00
tmshv 71738eab2a rm breadcrumbs style 2020-02-18 12:16:19 +03:00
tmshv 2287e59b71 rm ScheduleList component 2020-02-18 12:15:28 +03:00
tmshv e1778ba083 rm schedule-mobile style 2020-02-18 12:15:03 +03:00
tmshv 9829ccd4be Merge pull request #15 from tmshv/fix/merge-app-document
Merge _document with _app
2020-02-18 12:09:34 +03:00
tmshv 7b6fd8e892 clean style scss 2020-02-18 12:07:55 +03:00
tmshv 877e33c004 rm album.scss 2020-02-18 12:07:45 +03:00
tmshv dce6933904 rm main-image 2020-02-18 12:05:57 +03:00
tmshv 13781b3bbb disable importing tape-viewer 2020-02-18 12:02:00 +03:00
tmshv e146c5e0a4 rm timeline style 2020-02-18 12:01:43 +03:00
tmshv 71585c1d75 rm page-animation style 2020-02-18 12:01:31 +03:00
tmshv 8f2f30af77 rm parallax style 2020-02-18 12:01:20 +03:00
tmshv e05c06589f rm style from error page 2020-02-18 12:00:34 +03:00
tmshv 851d888f89 rm style from App component 2020-02-18 12:00:24 +03:00
tmshv 3856c80021 merge app with document 2020-02-18 12:00:12 +03:00
tmshv 678715cabb Merge pull request #14 from tmshv/fix/page-error-styles
Extract NotFound component with isolated style
2020-02-18 11:52:14 +03:00
tmshv f8373765fd extract NotFound component with isolated style 2020-02-18 11:46:33 +03:00
tmshv 6dfacb56c9 Merge pull request #11 from tmshv/fix/body-wrapper
body wrapper refactoring
2020-02-17 20:03:43 +03:00
tmshv 491ac743b5 Merge pull request #12 from tmshv/fix/rm-conf
rm old configs
2020-02-17 20:03:29 +03:00
tmshv 8d8232a866 rm nginx conf (we use now) 2020-02-17 19:58:13 +03:00
tmshv 91e9ff8a8d rm drone conf (we use now) 2020-02-17 19:58:05 +03:00
tmshv 2f23c65b9e rm app docker file (we use now) 2020-02-17 19:57:54 +03:00
tmshv 018b1fa8ba body wrapper refactoring 2020-02-17 19:45:34 +03:00
tmshv be60011567 v6.1.0 2020-02-15 07:27:14 +03:00
tmshv a91daa07d1 Merge pull request #9 from tmshv/feature/next-static-export
Next static export
2020-02-15 07:26:10 +03:00
tmshv 20436c4aad rm src/config 2020-02-15 07:20:51 +03:00
tmshv fe02f04217 .nowignore updated 2020-02-15 07:18:07 +03:00
tmshv 328c36a53a utils updated 2020-02-15 07:17:03 +03:00
tmshv 10f5e96616 Schedule component updated 2020-02-15 07:14:26 +03:00
tmshv a7edd93b00 .nowignore updated 2020-02-15 07:11:32 +03:00
tmshv 60a68bcb9a add babel conf 2020-02-15 07:05:03 +03:00
tmshv f7e6b3bc17 index page imports clean 2020-02-15 06:59:29 +03:00
tmshv fe3346e070 .gitignore update 2020-02-15 06:55:52 +03:00
tmshv 5b8e23f176 slug page format 2020-02-15 06:47:05 +03:00
tmshv deea0cc1d8 _error update 2020-02-15 06:43:03 +03:00
tmshv 6a86de6c84 Html component update 2020-02-15 06:40:47 +03:00
tmshv f874de73b9 gallery imports update 2020-02-15 06:34:46 +03:00
tmshv b778658479 documents imports optimisation 2020-02-15 06:33:29 +03:00
tmshv 44f51f907e gallery impors format 2020-02-15 06:33:19 +03:00
tmshv 0a9c0b632b rm now 2020-02-15 06:30:41 +03:00
tmshv f569152604 rm exportPathMap from next conf 2020-02-15 06:27:25 +03:00
tmshv 3d37276583 scripts fix 2020-02-15 06:26:36 +03:00
tmshv ca58994301 pages worked as static 2020-02-15 06:26:28 +03:00
tmshv b9c2929bc3 build scripts updated 2020-02-15 05:28:29 +03:00
tmshv 411f7eee62 dynamic page update 2020-02-15 05:28:16 +03:00
tmshv 2ca613e916 album page update 2020-02-15 05:28:06 +03:00
tmshv 42788cf8e4 next version update 2020-02-15 05:04:14 +03:00
tmshv 3103f3689b index page updated to static export 2020-02-15 04:41:59 +03:00
tmshv 4de352e2df rm unused after migrate to api 2020-02-15 04:35:19 +03:00
tmshv f3febbe3a9 rm server related part of next conf 2020-02-15 04:24:38 +03:00
tmshv 927201828c update package-lock 2020-02-15 04:23:57 +03:00
tmshv c0b43f8afd rm next based api; rm custom next server; rm koa 2020-02-15 04:23:22 +03:00
tmshv d3b5b2d5c6 createApiUrl signature changed 2020-02-15 04:04:26 +03:00
tmshv b4da11e086 api get page item changed 2020-02-15 03:46:17 +03:00
tmshv 744f127585 Merge branch 'master' into feature/next-static-export 2020-02-15 03:25:42 +03:00
tmshv 8ebac8f4a0 Merge pull request #10 from tmshv/fix/extract-api
API module
2020-02-15 03:24:06 +03:00
tmshv 64d783dede api tsconfig update 2020-02-15 03:22:49 +03:00
tmshv 2611a874de api ignore files updated 2020-02-15 03:22:21 +03:00
tmshv 48dab02c22 api conf update 2020-02-15 02:29:38 +03:00
tmshv 256dc70b1d api add dockerignore 2020-02-15 02:29:25 +03:00
tmshv afaf2d6bf4 api server fix 2020-02-15 02:29:16 +03:00
tmshv 1b104b7bab api add Dockerfile 2020-02-15 02:17:17 +03:00
tmshv 7f759989cb api gitignore 2020-02-15 02:17:03 +03:00
tmshv 43e8b0a790 api run update 2020-02-15 02:16:53 +03:00
tmshv d66f995683 api clean 2020-02-15 02:16:30 +03:00
tmshv 8a7cb50abd dev dep clean 2020-02-15 02:14:35 +03:00
tmshv 99b412ea8d api update 2020-02-15 01:58:42 +03:00
tmshv 502a314c68 factory update 2020-02-15 01:41:17 +03:00
tmshv 80b5297215 add factory 2020-02-15 01:40:07 +03:00
tmshv df2f979b55 add package-lock 2020-02-15 01:38:37 +03:00
tmshv fc0724a900 api copied to hudozka-api module based on express 2020-02-15 01:38:07 +03:00
tmshv 8de250ca7e add env 2020-02-14 19:37:00 +03:00
tmshv e6610fdabb ArticleCardList moved to tsx 2020-02-14 19:36:07 +03:00
tmshv c46fd4ddc5 core styles moved to css 2020-02-14 19:32:51 +03:00
tmshv a5a1493b3b Overlay refactoring 2020-02-13 22:42:05 +03:00
tmshv e45c69dee0 styles refactoring: move root to css file 2020-02-13 22:37:29 +03:00
tmshv 997e44483e initial static export in teachers 2020-02-13 17:31:23 +03:00
tmshv 92460592b4 person page imports updated 2020-02-13 00:05:16 +03:00
tmshv 68b6d36e0e collective page updated + ts 2020-02-12 23:43:25 +03:00
tmshv e375d305b8 lodash types 2020-02-12 23:42:53 +03:00
tmshv 657832e0e0 _app fixed and updated
- rm warning
- simplifyed
2020-02-12 23:35:31 +03:00
tmshv 5071b0292d _document refactoring + ts 2020-02-12 23:28:42 +03:00
tmshv effaf07ecb import from src 2020-02-12 23:28:28 +03:00
tmshv e6bf189aba update typescript to 3.7.5 2020-02-12 23:04:05 +03:00
tmshv e024dab95d delete unused dev packages 2020-02-12 23:03:16 +03:00
tmshv f16989c196 update next to 9.2.2-canary.16 2020-02-12 23:03:02 +03:00
tmshv 7b40c53c3a remove unused packages 2020-02-12 22:53:08 +03:00
tmshv 70007d3199 v6.0.0 2020-02-12 22:43:13 +03:00
tmshv b232a02549 Merge pull request #8 from tmshv/dev
Updated to Nextjs
2020-02-12 22:36:46 +03:00
tmshv dd70ad7025 Merge pull request #7 from tmshv/dependabot/pip/utils/Sync/pillow-6.2.0
Bump pillow from 3.3.0 to 6.2.0 in /utils/Sync
2020-02-12 22:32:26 +03:00
tmshv e6fbda5ae7 Merge branch 'dev' into dependabot/pip/utils/Sync/pillow-6.2.0 2020-02-12 22:32:14 +03:00
tmshv 48bbce1e91 add font reference to readme 2019-11-24 00:10:57 +03:00
tmshv 2768a1d109 title font size updated 2019-11-24 00:10:42 +03:00
tmshv 3457c30feb HudozkaTitle update 2019-11-23 23:56:47 +03:00
tmshv 180c9f34c5 person page updated + ts 2019-11-23 22:51:48 +03:00
tmshv 38f58b0b1d export routes updated 2019-11-23 22:40:01 +03:00
tmshv 569e775185 robots-txt script removed: public folder is serving natively 2019-11-23 22:30:11 +03:00
tmshv a0e92e066f static folder moved to public/static as last nextjs says 2019-11-23 22:29:10 +03:00
tmshv 308b832155 HudozkaTitle component layout updated 2019-11-23 22:23:20 +03:00
tmshv 950d0c4ffc withMiddleware updated 2019-11-23 22:23:07 +03:00
tmshv 0505c29eea mongodb package revert to 2.1.14 version 2019-11-23 22:22:18 +03:00
tmshv 6cfbc18029 documents page header 2019-11-23 21:30:48 +03:00
tmshv 402d1e5af7 added static routes to next config 2019-11-23 21:29:21 +03:00
tmshv 053f125ee4 npm audit fix force 2019-11-23 18:07:04 +03:00
tmshv 225269e3cd npm audit fix 2019-11-23 18:06:24 +03:00
tmshv 6d099bda10 npm update 2019-11-23 18:05:38 +03:00
tmshv a4810cc5da title font changed to Shadow 2019-11-23 18:02:01 +03:00
tmshv 21f9d1738c node-sass updated to 4.13.0 2019-11-23 17:51:41 +03:00
dependabot[bot] a52e25ee53 Bump pillow from 3.3.0 to 6.2.0 in /utils/Sync
Bumps [pillow](https://github.com/python-pillow/Pillow) from 3.3.0 to 6.2.0.
- [Release notes](https://github.com/python-pillow/Pillow/releases)
- [Changelog](https://github.com/python-pillow/Pillow/blob/master/CHANGES.rst)
- [Commits](https://github.com/python-pillow/Pillow/compare/3.3.0...6.2.0)

Signed-off-by: dependabot[bot] <support@github.com>
2019-10-22 20:31:03 +00:00
tmshv 7c6b755022 article scss style format 2019-10-21 15:33:06 +03:00
tmshv 5f7f90c879 added last articles 2019-10-21 15:26:56 +03:00
tmshv 8c2b17150b api articles typing fix 2019-10-21 15:24:14 +03:00
tmshv 5cbce648c4 Overlay fix no scroll 2019-10-21 15:23:31 +03:00
tmshv ef321453ef Page token property 2019-10-18 14:19:29 +03:00
tmshv dd0ec5f203 [sync] Image save by file not by hash 2019-10-17 18:51:08 +03:00
tmshv e9fa1376e3 [sync] Page model scan refactoring 2019-10-17 18:49:55 +03:00
tmshv 2601b8a54f [sync] fix sync order to prevent records deletion 2019-10-17 18:49:16 +03:00
tmshv 0f85b77d14 [sync] Sync item filter setup changed 2019-10-17 17:46:45 +03:00
tmshv 05e55d2668 wrapInitialProps typing 2019-10-17 17:12:54 +03:00
tmshv 0fab398ca6 Merge pull request #6 from tmshv/feature/upd1
Update 1
2019-10-17 17:06:17 +03:00
tmshv 2ca22419ec Meta component refactoring + typing 2019-10-17 17:05:48 +03:00
tmshv 17ca9123f5 Share component refactoring 2019-10-17 16:55:12 +03:00
tmshv 473c4047be teacher page imports bugfix + rm unused 2019-10-17 16:51:56 +03:00
tmshv 42322feced content sizes for mobile refacoting
moved from scss file to _app global style
2019-10-17 16:51:09 +03:00
tmshv 9a5056a362 content style format 2019-10-17 16:44:52 +03:00
tmshv 22689425e3 PersonCard mobile layout fix 2019-10-17 15:26:28 +03:00
tmshv 2378b4476e gallery page updated 2019-10-17 15:25:23 +03:00
tmshv 237a67de01 gallery page to tsx 2019-10-17 15:09:57 +03:00
tmshv 6b8f6e8b66 index page typings 2019-10-17 15:08:53 +03:00
tmshv 4e076b787e next page cleanup 2019-10-17 15:08:34 +03:00
tmshv 436b58cede HudozkaTitle component update
- moved to typescript
- uses memo
2019-10-17 14:54:59 +03:00
tmshv 3902815113 App layout prop update 2019-10-17 14:50:09 +03:00
tmshv 228e7824de App component update; support reduced-motion 2019-10-17 14:33:28 +03:00
tmshv 96c1330d9b remove unused page.scss 2019-10-17 14:32:48 +03:00
tmshv 0e7b312d97 Page component updated + ts 2019-10-17 12:55:28 +03:00
tmshv 8163c35efe article card layout updated 2019-10-17 12:39:09 +03:00
tmshv 95b5b56fd4 ArticleCard style format 2019-10-17 12:35:12 +03:00
tmshv 0207f85f00 ArticleCard Date component refactoring + moved to separate file 2019-10-17 12:33:09 +03:00
tmshv 9fb815081c ArticleCard image refactoring 2019-10-17 12:28:32 +03:00
tmshv 3dfca4c3e2 HudozkaTitle text update 2019-10-16 15:47:28 +03:00
tmshv 2fc59dc082 Show hide menu button over overlay 2019-10-16 02:31:54 +03:00
tmshv ddd6c9daa3 Menu component update 2019-10-16 01:23:45 +03:00
tmshv feb59b8b8e update menu to differentiate mobile and desktop layout 2019-10-16 01:13:20 +03:00
tmshv 4d7fc57934 MenuToggle moved to separate component 2019-10-15 23:21:33 +03:00
tmshv fbcf204642 overlay reduced motion support 2019-10-15 23:05:31 +03:00
tmshv bdde0f79c1 fix Overlay lag effect 2019-10-15 22:59:11 +03:00
tmshv 30f1274405 Overlay refactoring and improvement 2019-10-15 22:55:47 +03:00
tmshv 04d6c8d223 Overlay moved to separate component 2019-10-15 22:18:52 +03:00
tmshv f96b495b38 Overlay transition 2019-10-15 22:07:34 +03:00
tmshv a597a0d061 api article fix missing import; js -> ts 2019-10-15 22:07:13 +03:00
tmshv d2f9a39d33 Menu mobile container updated 2019-10-15 07:10:03 +03:00
tmshv bf1c9c20ed Menu Overlay component added 2019-10-15 07:05:04 +03:00
tmshv 10e7dfbbfa App component update. Move menu to dynamic container 2019-10-15 07:04:50 +03:00
tmshv 673bb83ab8 Footer component moved to ts 2019-10-15 07:04:24 +03:00
tmshv 07df3bfa8f App component moved to ts 2019-10-15 06:55:40 +03:00
tmshv 8c63e249b9 Menu cleanup 2019-10-15 06:36:32 +03:00
tmshv df2fec4999 Menu show toggle on mobile only 2019-10-15 06:36:25 +03:00
tmshv 64b51363a8 MenuToggle fix 2019-10-15 06:32:46 +03:00
tmshv 7c320b98da Menu margin update 2019-10-15 06:09:48 +03:00
tmshv 38f2c24167 rm unused accessibility control style 2019-10-15 06:01:24 +03:00
tmshv c0303b6a40 rm unuses hmenu scss 2019-10-15 05:57:56 +03:00
tmshv b4349cde12 Menu rm unused effect 2019-10-15 05:54:04 +03:00
tmshv 792be94a79 Menu component layout updated 2019-10-15 05:47:01 +03:00
tmshv 9ca50e87c2 all menu style moved to jsx 2019-10-15 05:32:33 +03:00
tmshv cdd76789c6 menu selected style moved to styles jsx 2019-10-15 05:28:12 +03:00
tmshv 4586ac0bdc rm main-menu submenu styles 2019-10-15 05:23:49 +03:00
tmshv 0699df1754 rm accessibility themes 2019-10-15 05:23:02 +03:00
tmshv 12782e9869 main-menu style format 2019-10-15 05:22:21 +03:00
tmshv ab577fa263 Menu update. Use react hooks, not client based script. 2019-10-15 04:39:20 +03:00
tmshv 0f1438e8db MenuToggle component works 2019-10-15 03:45:18 +03:00
tmshv 52ffa79cb4 Menu component ts 2019-10-15 03:11:57 +03:00
tmshv c98d69a483 HudozkaTitle fix mobile 2019-10-15 03:10:32 +03:00
tmshv cc32215fdd ArticleCard component style fix + ts 2019-10-15 02:51:15 +03:00
tmshv 5d672842f3 mobile style variables 2019-10-15 02:46:41 +03:00
tmshv a6e528d59b variables scss format 2019-10-15 02:26:55 +03:00
tmshv 9b642a38ce main scss format 2019-10-15 02:21:02 +03:00
tmshv ed9dae3760 documents page fixed 2019-10-15 02:12:56 +03:00
tmshv eed3a3c007 Album model to ts 2019-10-15 01:27:43 +03:00
tmshv aa22f882bd classnames typings 2019-10-15 01:23:25 +03:00
tmshv 011b24e9ae api image clean 2019-10-15 01:23:16 +03:00
tmshv b5a36e663d fix wrong large image path 2019-10-15 01:23:06 +03:00
tmshv 0ff7d40cb2 CollectiveImage component fix 2019-10-15 01:22:46 +03:00
tmshv e20636b4f1 Image component written in ts 2019-10-15 01:22:33 +03:00
tmshv 873c4ce65c Image model findByFile typings improve 2019-10-15 01:22:17 +03:00
tmshv 5f637b4097 PersonCard component fix image 2019-10-15 01:02:46 +03:00
tmshv c48de3e09a Teacher model moved to typescript. Page can be loaded but looks ugly due to broken styled jsx 2019-10-15 00:47:57 +03:00
tmshv f48f89ff1b server loads all Pages on start as it was before 2019-10-15 00:43:33 +03:00
tmshv d1d0011cc9 Page model fix wrong imports 2019-10-15 00:43:02 +03:00
tmshv b0657c7fa4 Article typings improve 2019-10-15 00:42:47 +03:00
tmshv c038ef882b Data::getStore generic 2019-10-15 00:42:35 +03:00
tmshv 717540682d core Data typings 2019-10-15 00:35:27 +03:00
tmshv bf1fd90133 mongodb typings 2019-10-15 00:35:16 +03:00
tmshv f72652440e make Config working right. Article model looks restored 2019-10-15 00:31:56 +03:00
tmshv d4f6568269 fix ArticleCard to properly works with styled jsx. Image component inlined 2019-10-15 00:24:27 +03:00
tmshv 5831275b7a updated to make index page working 2019-10-15 00:16:55 +03:00
tmshv 7363d7c0ec api articles -> server articles 2019-10-14 23:46:09 +03:00
tmshv b35e4e36e2 unstable typescript 2019-10-14 23:42:43 +03:00
tmshv 274e1e7fc0 hudozka title style moved to styled jsx 2019-10-14 22:33:02 +03:00
tmshv 9bdacb4493 Image model logger refactoring 2019-10-14 22:24:23 +03:00
tmshv aecd72847c [sync] model build moved to separate step 2019-10-14 21:07:23 +03:00
tmshv d122d040fe [sync] sync options moved from run parameters to instance fields 2019-10-14 20:42:05 +03:00
tmshv 4c4e800d19 [sync] changed_items renamed to items 2019-10-14 20:34:09 +03:00
tmshv 5b4f36a419 rm unused TimelinePostIntagram 2019-10-14 20:29:44 +03:00
tmshv 8ba8a9af57 App reformat, js -> jsx 2019-10-14 18:31:15 +03:00
tmshv 36ed564231 Menu component refactoring 2019-10-14 18:24:00 +03:00
tmshv 3f4ffdb93a Menu component format 2019-10-14 18:18:45 +03:00
tmshv 34354e9577 Menu component update
js -> jsx
update imports
no default import
2019-10-14 18:17:39 +03:00
tmshv 7ce46cbae2 Schedule component js -> jsx 2019-10-14 18:15:55 +03:00
tmshv f16d91c5ad Schedule component bugfix: add missing key prop 2019-10-14 17:55:52 +03:00
tmshv faa17a3e79 Schedule component format 2019-10-14 17:54:50 +03:00
tmshv 04c269b64a Schedule component no default export 2019-10-14 17:54:26 +03:00
tmshv 7df8ec73ec PersonCard export updated 2019-10-14 17:52:04 +03:00
tmshv 1f2b61cc29 schedule/collective files move to server 2019-10-14 17:47:02 +03:00
tmshv c1d8ab3b97 Schedule component updated imports 2019-10-14 17:45:52 +03:00
tmshv ac02ab3f1a rm unused TeacherProfile 2019-10-14 17:45:24 +03:00
tmshv 0c41bffb75 add to middlewares withCollection (unstable) 2019-10-14 17:45:00 +03:00
tmshv c77dc74965 rm lib/component 2019-10-14 17:44:03 +03:00
tmshv f3b20b88f6 server.js EOF 2019-10-14 17:23:27 +03:00
tmshv 285475762e ArticleCardList style moved to styled jsx 2019-10-14 17:23:16 +03:00
tmshv 4fc424b145 core/Teacher format 2019-10-14 17:14:45 +03:00
tmshv 57454962f1 core/schedule moved to server/schedule 2019-10-14 16:51:31 +03:00
tmshv fab2b8033e now conf EOF 2019-10-14 16:34:55 +03:00
tmshv bb18eb3778 now conf removed alias 2019-10-14 16:34:49 +03:00
tmshv 64f9ba7a21 AlbumImage size calculation 2019-10-14 16:34:28 +03:00
tmshv ea5055b46c [sync] create_post html renamed to tree 2019-10-14 16:33:45 +03:00
tmshv 21db9a91b3 [sync] hash_salt_images increased 2019-10-14 16:32:48 +03:00
tmshv 22d9757dc3 [sync] hash_salt_document increased 2019-10-14 16:32:34 +03:00
tmshv a898dc446f [sync] Document upload clean 2019-10-14 16:31:00 +03:00
tmshv a70967f37d [sync] create_image image_processing_enabled supported 2019-10-14 16:30:35 +03:00
tmshv bb0a9a00f6 [sync] Image upload refactoring 2019-10-14 16:29:56 +03:00
tmshv c3cbdd24ff [sync] art.shlisselburg.org host changed to static.shlisselburg.org 2019-10-14 14:53:50 +03:00
tmshv f9a4b65452 [sync] one of logger message was changed 2019-10-14 14:53:03 +03:00
tmshv f3062f7379 [sync] support custom item filter function 2019-10-14 14:52:17 +03:00
tmshv b052d48e1e removed “based on” section 2019-10-13 22:26:03 +03:00
tmshv 2c57f772aa Merge branch 'dev' of github.com:tmshv/hudozka into dev 2019-10-13 22:20:04 +03:00
tmshv 1c25448014 [sync] pillow version updated 2019-10-13 22:19:53 +03:00
tmshv 33b5c1ebe5 package.json EOF 2019-10-13 22:19:34 +03:00
tmshv db8e187861 eslint version updated 2019-10-13 22:19:25 +03:00
tmshv 656fc1eb2c Merge pull request #4 from tmshv/dependabot/pip/utils/Sync/pyyaml-5.1
Bump pyyaml from 3.11 to 5.1 in /utils/Sync
2019-10-13 22:17:04 +03:00
tmshv 09ba4cb710 Merge branch 'dev' into dependabot/pip/utils/Sync/pyyaml-5.1 2019-10-13 22:16:42 +03:00
tmshv da713304fd Merge branch 'dev' of github.com:tmshv/hudozka into dev 2019-10-13 22:11:36 +03:00
tmshv d40c0855cb added dockerignore 2019-10-13 22:10:42 +03:00
tmshv 8d534a1cd2 added nowignore 2019-10-13 22:10:29 +03:00
tmshv ed355c4de2 Merge pull request #5 from tmshv/dependabot/pip/utils/Sync/requests-2.20.0
Bump requests from 2.10.0 to 2.20.0 in /utils/Sync
2019-10-13 21:38:05 +03:00
tmshv 249f002551 Merge branch 'master' of github.com:tmshv/hudozka 2019-10-13 21:30:04 +03:00
dependabot[bot] e053f06300 Bump requests from 2.10.0 to 2.20.0 in /utils/Sync
Bumps [requests](https://github.com/requests/requests) from 2.10.0 to 2.20.0.
- [Release notes](https://github.com/requests/requests/releases)
- [Changelog](https://github.com/psf/requests/blob/master/HISTORY.md)
- [Commits](https://github.com/requests/requests/compare/v2.10.0...v2.20.0)

Signed-off-by: dependabot[bot] <support@github.com>
2019-10-13 18:20:28 +00:00
dependabot[bot] c8b0ad3731 Bump pyyaml from 3.11 to 5.1 in /utils/Sync
Bumps [pyyaml](https://github.com/yaml/pyyaml) from 3.11 to 5.1.
- [Release notes](https://github.com/yaml/pyyaml/releases)
- [Changelog](https://github.com/yaml/pyyaml/blob/master/CHANGES)
- [Commits](https://github.com/yaml/pyyaml/compare/3.11...5.1)

Signed-off-by: dependabot[bot] <support@github.com>
2019-10-13 18:20:24 +00:00
tmshv 3f90e35336 Merge pull request #3 from tmshv/dev
Nextjs version
2019-10-13 21:19:11 +03:00
tmshv 0603f64b4c rm unused src/routes/schedule 2019-10-13 20:53:18 +03:00
tmshv 71c9ec964a page documents clean 2019-10-13 20:30:33 +03:00
tmshv c97c7d14a0 added now config 2019-10-13 19:57:47 +03:00
tmshv 6c201f9305 next-lib refactoring 2019-10-13 19:57:25 +03:00
tmshv fe5cc36182 added wrapper to getInitialProps to prevent api calls in production 2019-10-13 19:48:52 +03:00
tmshv dded475c47 build config updated
copying robots.txt moved to separate script
export script merged with build script
2019-10-13 18:35:01 +03:00
tmshv 0ae9601309 Article component format 2019-10-13 18:26:48 +03:00
tmshv 281940942f album.js -> album.jsx 2019-10-13 16:36:14 +03:00
tmshv 97106dd427 article page get initial props stability improvement 2019-10-13 16:30:34 +03:00
tmshv 40519b9c46 collective page get initial props stability improvement 2019-10-13 16:30:17 +03:00
tmshv d82201d131 next-lib ; rm 2019-10-13 16:18:04 +03:00
tmshv a70abcd64a next config export trailing slash enabled 2019-10-13 16:13:38 +03:00
tmshv f78deffbd5 next-lib requestGet fix & refactoring 2019-10-13 16:13:09 +03:00
tmshv 44d2ba7bff articles page default articles 2019-10-13 16:12:42 +03:00
tmshv 6352ca66d9 index page default articles list 2019-10-13 16:12:28 +03:00
tmshv 7ab68f5a8e getInitialProps request stability improvements 2019-10-12 06:21:02 +03:00
tmshv 95c8369df2 add withMiddleware for all api routes. Now it do nothing 2019-10-12 04:58:56 +03:00
tmshv cd7536f74f fix broken build due to wrong App import in album page 2019-10-12 04:56:37 +03:00
tmshv 01b9064700 core db optimisation 2019-10-12 02:17:24 +03:00
tmshv 9925d4dc8b removed unused coverage tool
TODO: move to jest later
2019-10-12 01:31:01 +03:00
tmshv 2445aa5aa9 removed unused gulp and other build related packages 2019-10-12 01:26:36 +03:00
tmshv a502ddd4df next pages uses absolute url resolver to access api from getInitialProps 2019-10-11 23:14:01 +03:00
tmshv 28a4d05fe4 articles pages default page size 2019-10-11 21:55:53 +03:00
tmshv 2c1306ba2f index page default page size 2019-10-11 21:55:27 +03:00
tmshv fd126998bd [Sync] run options refactoring 2019-08-05 18:54:13 +03:00
tmshv d8716b71e2 [Sync] added sync-smart (unstable) 2019-08-05 18:24:12 +03:00
tmshv bd81d696b8 [Sync] settings update 2019-08-05 18:08:20 +03:00
tmshv b01172f405 gitignore update 2019-08-05 17:55:39 +03:00
tmshv 68e0fd5dd5 Image component update 2019-08-05 17:26:37 +03:00
tmshv 800f43bd8a lib menu update 2019-08-05 17:26:14 +03:00
tmshv 94d06aa8cd mapOf moved to server lib 2019-08-05 17:25:51 +03:00
tmshv 04db0114e7 PersonCard style cleanup 2019-08-05 17:24:16 +03:00
tmshv f0f33fe201 ArticleCard + ArticleCardList refactoring 2019-08-05 17:23:30 +03:00
tmshv 0ea937847a HudozkaTitle refactoring 2019-08-05 17:22:43 +03:00
tmshv 28967ada51 collective page format 2019-08-05 17:22:10 +03:00
tmshv 8ca8b43f12 index page title format 2019-08-05 17:21:50 +03:00
tmshv b6f70568fb package.json 4 spaces 2019-08-05 16:46:54 +03:00
tmshv 1da972f0ea core db removed unused 2019-08-05 16:41:21 +03:00
tmshv 55406b2b18 App component refactoring 2019-08-05 15:43:33 +03:00
tmshv 6a87513703 PersonCardList -> CardList + refactoring 2019-08-05 15:36:02 +03:00
tmshv e76d55c0a7 CollectiveImage refactoring 2019-08-05 15:35:28 +03:00
tmshv 27bbdad7b1 PersonCard refactoring 2019-08-05 15:34:30 +03:00
tmshv 24773f0c65 ArticleCard hover effect refactored to width/height scale to fix Safari bug with transform+transition+border-radius 2019-08-05 15:20:12 +03:00
tmshv 904555d1b6 packages removed 2019-08-04 20:43:22 +03:00
tmshv 54cfe7f2d0 ArticleCard refactoring + style update 2019-08-04 20:42:59 +03:00
tmshv 2ab341cd71 rm middleware/error 2019-08-04 19:57:27 +03:00
tmshv bdf9b29f1e rm lib/render 2019-08-04 19:57:17 +03:00
tmshv 56e21000a5 rm services/Instagram 2019-08-04 18:19:29 +03:00
tmshv 4e13a18072 rm modules/Feed 2019-08-04 17:55:02 +03:00
tmshv 0a7a9587fc + feed script 2019-08-04 17:53:55 +03:00
tmshv 29a9383756 rm gulpfile 2019-08-03 19:04:12 +03:00
tmshv fee7a4f6da nginx + dockerfile update 2019-08-03 19:03:39 +03:00
tmshv 1b77f6b2de robots.txt + sitemap.xml 2019-08-03 19:02:07 +03:00
tmshv 5ab2084763 404 page update 2019-08-03 19:01:15 +03:00
tmshv 1736fcb899 _document meta fix 2019-08-03 16:58:16 +03:00
tmshv 5ecff7fc4d next config option updated 2019-08-03 03:07:26 +03:00
tmshv 5aff7d0fe7 lib menu export updated 2019-08-03 03:06:57 +03:00
tmshv 46258f7f94 Meta component update 2019-08-03 03:05:49 +03:00
tmshv aa596b5859 teacher page meta update 2019-08-03 02:57:03 +03:00
tmshv e67d8ab40e api person update 2019-08-03 02:56:53 +03:00
tmshv 464485a52c articles page meta 2019-08-03 02:51:30 +03:00
tmshv 2eab1d18a7 document page meta 2019-08-03 02:51:30 +03:00
tmshv 1b96796ef0 rm main.hbs 2019-08-03 02:51:30 +03:00
tmshv ced4e47d54 teacher page meta 2019-08-03 02:49:09 +03:00
tmshv 4ee2ec7d74 article page meta 2019-08-03 00:26:40 +03:00
tmshv 33ee2d218e article api preview update 2019-08-03 00:26:27 +03:00
tmshv d29bfbff89 page meta 2019-08-03 00:19:19 +03:00
tmshv e42f739797 api page update 2019-08-03 00:18:55 +03:00
tmshv 7fb04d8ffa gallery page meta 2019-08-02 23:46:51 +03:00
tmshv d732777748 documents page clean 2019-08-02 23:40:45 +03:00
tmshv 5708f778c7 documents page meta 2019-08-02 23:40:33 +03:00
tmshv f2802c87a8 collective page refactoring 2019-08-02 23:35:09 +03:00
tmshv 866d82f44c collective meta 2019-08-02 21:29:43 +03:00
tmshv 2f3676f123 collective image uses new api 2019-08-02 21:29:31 +03:00
tmshv bab4f6cb3c YMetrika script fix 2019-08-02 21:28:47 +03:00
tmshv 8d67fbefd1 api image update 2019-08-02 21:28:33 +03:00
tmshv ed1a924156 articles page head 2019-08-02 19:43:10 +03:00
tmshv 0661780117 rm src/render 2019-08-02 19:37:25 +03:00
tmshv 3ba574a147 Meta component update 2019-08-02 19:29:12 +03:00
tmshv d3fff01b14 home page meta 2019-08-02 18:31:34 +03:00
tmshv a10ea32af3 home page url hardcoded 2019-08-02 18:31:14 +03:00
tmshv aed6c1aac7 removed old api/pages 2019-08-02 18:31:00 +03:00
tmshv 3ca52d6903 added Meta component 2019-08-02 18:30:47 +03:00
tmshv 85439ced56 added google analytics 2019-08-02 17:52:56 +03:00
tmshv 61db139a0d fotorama script ordering fix 2019-08-02 17:52:44 +03:00
tmshv a31d8b3fa5 _document format 2019-08-02 17:52:28 +03:00
tmshv 2c9f5f08d4 YMetrika refactoring 2019-08-02 17:50:00 +03:00
tmshv f4008a4750 yandex metrika 2019-08-02 17:41:45 +03:00
tmshv 2d847ed46f client app file update 2019-08-02 17:41:30 +03:00
tmshv 77dd528982 3rdparty -> static + _document links 2019-08-02 17:21:30 +03:00
tmshv c2000bcb31 added favicons 2019-08-02 17:14:09 +03:00
tmshv 049c0f4aad populating head with meta tags 2019-08-02 16:34:45 +03:00
tmshv a291899f52 schedule title 2019-08-02 16:23:48 +03:00
tmshv ecd6efd4fd teacher title 2019-08-02 16:23:41 +03:00
tmshv 7c3f3542ac page title 2019-08-02 16:23:30 +03:00
tmshv 1c65440536 gallery title 2019-08-02 16:23:20 +03:00
tmshv b0542dfe80 documents title 2019-08-02 16:23:12 +03:00
tmshv 3da16a0a86 document title 2019-08-02 16:23:02 +03:00
tmshv 69dcb8793a collective title 2019-08-02 16:22:53 +03:00
tmshv b1d8b2483e article title 2019-08-02 16:22:41 +03:00
tmshv ae48ee1842 album title 2019-08-02 16:22:31 +03:00
tmshv e366830677 home page size query 2019-08-02 16:08:13 +03:00
tmshv 07cd42abc1 next config refactoring 2019-08-02 16:08:13 +03:00
tmshv 4378d49681 home page title 2019-08-02 16:08:13 +03:00
tmshv ef9618d443 edit.hbs removed 2019-08-02 16:08:13 +03:00
tmshv 862118fe1c core Document format 2019-08-02 16:08:13 +03:00
tmshv d04c61aef5 next config updated; added exportPathMap 2019-08-02 16:07:48 +03:00
tmshv 869b65635c npm start script updated 2019-08-02 15:32:10 +03:00
tmshv 27722ae87c articles page pageSize from query 2019-08-02 15:31:58 +03:00
tmshv 56a6735bfd api articles returns totalPages 2019-08-02 15:31:37 +03:00
tmshv a2b5b2a39a added lodash 2019-08-02 15:25:31 +03:00
tmshv 962780aeb1 hardcoded page url 2019-08-02 15:21:11 +03:00
tmshv 7599e9d41f api articles urls fix 2019-08-01 17:41:37 +03:00
tmshv 4443a5ca18 rm index entrypoint 2019-08-01 17:40:32 +03:00
tmshv b90b2a3e77 api pages 2019-08-01 17:40:17 +03:00
tmshv 606164bb43 api persons urls 2019-08-01 17:39:53 +03:00
tmshv 1be8911070 api pages urls 2019-08-01 17:39:44 +03:00
tmshv 4043682c3d api files urls 2019-08-01 17:39:14 +03:00
tmshv 7e1a5c7af0 api articles urls 2019-08-01 17:39:08 +03:00
tmshv 579021658b api albums urls 2019-08-01 17:38:58 +03:00
tmshv 0713bad871 connect fn update 2019-08-01 17:10:50 +03:00
tmshv 43af2996bf app moved to next.js 2019-08-01 14:44:25 +03:00
tmshv dcca513aea lib array old export 2019-08-01 14:39:10 +03:00
tmshv d8cf5c7525 getPathWithNoTrailingSlash defaults 2019-08-01 14:36:37 +03:00
tmshv 5ad84cd61e core Document format 2019-08-01 01:39:20 +03:00
tmshv 28627bfa85 gitignore update 2019-07-31 23:13:52 +03:00
tmshv 4313650e69 removed draft.js packages 2019-07-31 19:05:50 +03:00
tmshv 30efb94287 Update from Forestry.io
Roman Timashev updated data/articles/article-test.md
2019-07-31 14:46:34 +00:00
tmshv 3023f30225 Update from Forestry.io
Roman Timashev updated data/articles/article-test.md
2019-07-31 14:45:28 +00:00
tmshv 4560b35b05 Update from Forestry.io
Roman Timashev created uploads/2019/Устав 2015.pdf
2019-07-31 14:44:55 +00:00
tmshv c8a0f19b3c Update from Forestry.io - Updated Forestry configuration 2019-07-31 14:42:13 +00:00
tmshv e47856398b Rename data/articles/settings.json to data/settings.json 2019-07-31 17:41:56 +03:00
tmshv 071dfaee9e Update from Forestry.io - Updated Forestry configuration 2019-07-31 14:38:27 +00:00
tmshv 07ec977efd Create settings.json 2019-07-31 17:37:31 +03:00
tmshv 73161efaf2 Update from Forestry.io
Roman Timashev updated data/articles/article-test.md
2019-07-31 14:35:12 +00:00
tmshv e73f5ce40e Update from Forestry.io - Updated Forestry configuration 2019-07-31 14:34:15 +00:00
tmshv f37fc02067 Update from Forestry.io - Updated Forestry configuration 2019-07-31 14:33:32 +00:00
tmshv a8d879c3f5 Update from Forestry.io
Roman Timashev created data/articles/article-test.md
2019-07-31 14:08:47 +00:00
tmshv 70004146e4 Update from Forestry.io - Updated Forestry configuration 2019-07-31 14:07:20 +00:00
tmshv b570f413a9 Update from Forestry.io - Updated Forestry configuration 2019-07-31 14:06:35 +00:00
tmshv 4e9cb7a033 Update from Forestry.io - Updated Forestry configuration 2019-07-31 14:05:38 +00:00
tmshv 33651018e3 Update from Forestry.io - Updated Forestry configuration 2019-07-31 14:03:20 +00:00
tmshv 12accfee3f Update from Forestry.io
Roman Timashev created uploads/2019/HudozkaMain2014.jpg
2019-07-31 14:00:38 +00:00
tmshv 2925eb7469 Update from Forestry.io - Updated Forestry configuration 2019-07-31 13:58:47 +00:00
tmshv 16501372ae Update from Forestry.io - Updated Forestry configuration 2019-07-31 13:24:40 +00:00
tmshv 2933cb2e07 Update from Forestry.io - Updated Forestry configuration 2019-07-31 12:15:59 +00:00
tmshv f05aea3b04 npm audit fix 2019-07-17 16:43:55 +03:00
tmshv 1dab596bc6 next updated to 9.0.2 2019-07-17 16:43:02 +03:00
tmshv 79891891b9 Html component format 2019-07-17 16:41:06 +03:00
tmshv aabed9d686 next config added 2019-07-17 16:39:58 +03:00
tmshv b05c5856c2 packages update 2019-07-17 16:39:40 +03:00
tmshv dd8091abfc buildMenu path fix 2019-05-30 19:09:19 +03:00
tmshv 9dc776f1b3 getHtml moved to Html component 2019-05-30 18:49:11 +03:00
tmshv 81518fd57e lib render refactoring: extract buildMenu to lib/menu 2019-05-30 17:27:23 +03:00
tmshv 10166293df deleted edit code; added next config; refactoring 2019-05-30 03:00:30 +03:00
tmshv 85968e0609 handle db page not found improved 2019-05-30 00:25:39 +03:00
tmshv cbc00bee03 server app renamed to server 2019-05-30 00:13:01 +03:00
tmshv 83c7972877 http server creation refactoring 2019-05-30 00:04:15 +03:00
tmshv a3505abd46 index bootscrap function refactoring 2019-05-29 23:58:51 +03:00
tmshv 0cce97ac00 added dev script; babelrc update to use last object-rest-spread plugin 2019-05-29 23:55:22 +03:00
tmshv b1ce3a38ec deleted obsolette configs 2019-05-29 23:38:57 +03:00
tmshv 3f27d6f5ad koa updated to 2.7 2019-05-29 23:37:17 +03:00
tmshv 157f522b9b react updated to 16.8 2019-05-29 23:36:35 +03:00
tmshv beca1919da npm audit fix force 2019-05-29 23:35:43 +03:00
tmshv 88954f060f npm audit fix 2019-05-29 23:34:15 +03:00
tmshv 49cb2b349d package-lock updated 2019-05-29 23:32:59 +03:00
tmshv 2e474d4b56 hudozka package renamed to hudozka 2019-05-29 23:31:02 +03:00
tmshv 89395b8681 hudozka version changed to 5.0.0 2019-05-29 23:30:42 +03:00
tmshv 701f786f07 Merge pull request #2 from tmshv/dev
v4 last updates
2019-05-29 23:28:03 +03:00
tmshv 1bca661e13 [sync] upload driver changed to s3 2019-05-29 23:06:57 +03:00
tmshv dbadbdafc3 sync yandexdisk api extended from 2018.05 2019-05-29 23:05:06 +03:00
tmshv 759f1217b5 hudozka app added edit from 2018.02 2019-05-29 22:29:21 +03:00
tmshv 6805e07434 packages update 2019-02-24 04:15:01 +03:00
tmshv f976001c41 [sync] image url base changed + cleanup 2019-01-24 19:12:13 +03:00
tmshv af4ccd29d7 [sync] hash salt updates 2019-01-24 19:11:51 +03:00
tmshv 07f65a0043 Merge branch 'dev' of tmshv/hudozka into master 2018-05-23 07:39:15 +00:00
tmshv 3002e9817f Merge branch 'dev' of tmshv/hudozka into master 2018-05-23 07:29:04 +00:00
tmshv fe9a18dd03 Merge branch 'dev' of tmshv/hudozka into master 2018-05-23 00:06:53 +00:00
tmshv 19952b72f1 Merge branch 'dev' of tmshv/hudozka into master 2018-05-22 23:56:21 +00:00
tmshv 6668b5e861 Merge pull request #1 from tmshv/dev
4.0
2018-01-04 23:35:03 +03:00
384 changed files with 13902 additions and 22838 deletions

No files matched your search

+1 -13
View File
@@ -1,17 +1,5 @@
{
"presets": [
[
"env",
{
"targets": {
"node": "8.5.0"
}
}
]
],
"plugins": [
"transform-react-jsx",
"transform-object-rest-spread",
"transform-class-properties"
"next/babel"
]
}
-18
View File
@@ -1,18 +0,0 @@
pipeline:
build:
image: docker
commands:
- docker build -t tmshv/hudozka:latest -t tmshv/hudozka:build-${DRONE_BUILD_NUMBER} .
- docker save -o hudozka-docker_container${DRONE_BUILD_NUMBER}.tar tmshv/hudozka:build-${DRONE_BUILD_NUMBER}
volumes:
- /var/run/docker.sock:/var/run/docker.sock
scp:
image: appleboy/drone-scp
host: art.shlisselburg.org
username: master
target: ~/Hudozka
source: hudozka-docker_container${DRONE_BUILD_NUMBER}.tar
secrets: [scp_key]
when:
branch: master
-4
View File
@@ -9,10 +9,6 @@ module.exports = {
"promise",
"react",
],
"globals": {
"angular": true,
"DISQUS": true
},
"rules": {
"semi": ["error", "never"],
"space-before-function-paren": "off",
@@ -0,0 +1,15 @@
---
label: Article
hide_body: false
fields:
- name: slug
type: text
config:
required: false
label: slug
- name: tags
type: tag_list
default: []
label: tags
pages:
- data/articles/article-test.md
+29
View File
@@ -0,0 +1,29 @@
---
new_page_extension: md
auto_deploy: false
admin_path: ''
webhook_url:
sections:
- type: directory
path: data/articles
label: Articles
create: documents
match: "**/*"
- type: document
path: data/settings.json
label: Settings
upload_dir: uploads
public_path: "/uploads"
front_matter_path: ''
use_front_matter_path: false
file_template: ":year:/:filename:"
build:
preview_command: gatsby build
publish_command: gatsby build
preview_output_directory: public
output_directory: public
instant_preview_command: npm run forestry:preview
install_dependencies_command: yarn install
preview_docker_image: node:10
mount_path: "/srv"
working_dir: "/srv"
+4 -1
View File
@@ -8,12 +8,15 @@ private*.json
/node_modules
/bower_components
/modules/hudozka-api-v1/lib
/public
/build
/out
dist
.next
**/env
**/venv
**/__pycache__
**/*.pyc
/coverage
**/.vscode
*.log
.now
+5
View File
@@ -0,0 +1,5 @@
.forestry
./utils
modules
data
uploads
-27
View File
@@ -1,27 +0,0 @@
# Build
FROM node:10 as build
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm i
COPY webpack.config.js gulpfile.js .babelrc ./
COPY robots.txt ./
COPY src ./src
RUN npm run gulp
RUN npm run build-app
RUN npm run out
# Run
FROM node:8-alpine
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm i --production
COPY --from=build /app/out ./src
COPY --from=build /app/public ./public
EXPOSE 3000
CMD npm start
+2 -6
View File
@@ -2,6 +2,8 @@
Site of Art school of Shlisselburg
Font: [«Shadow»](http://mishapanfilov.ru/font_shadow.html)
## Usage
### Build
@@ -36,11 +38,5 @@ PWD=<mongo_password>
mongodump -d ${DB} --gzip --archive | mongorestore -h ${HOST} -u ${USER} -p ${PWD} -d ${DB} --gzip --archive
```
## Based on:
- [NodeJS](http://nodejs.org) 10.0
- [koa.js](http://koajs.com) 2.0
- [React](https://react.org) 16.3
- [MongoDB](http://mongodb.org) 3.6
## Contributors
- Roman Timashev ([roman@tmshv.ru](mailto:roman@tmshv.ru))
+16
View File
@@ -0,0 +1,16 @@
---
tags:
- test
- dev
slug: article-test
---
This is **Hudozka**
![](/uploads/2019/HudozkaMain2014.jpg)
1. 1
2. 2
3. 3
[Устав 2015](https://app.forestry.io/sites/tadnt0fp3fdrgg/body-media//uploads/2019/Устав 2015.pdf "Устав 2015")
+3
View File
@@ -0,0 +1,3 @@
{
"name": "Hudozka"
}
-30
View File
@@ -1,30 +0,0 @@
version: '3'
volumes:
data:
services:
mongo:
image: mongo:3.6
restart: always
volumes:
- data:/data/db
ports:
- "1817:27017"
environment:
- MONGO_INITDB_ROOT_USERNAME=hudozka
- MONGO_INITDB_ROOT_PASSWORD=${MONGO_HUDOZKA_PASSWORD}
app:
restart: always
depends_on:
- mongo
build:
context: ./
dockerfile: Dockerfile
links:
- mongo
ports:
- "1880:3000"
environment:
- DB_URI=${HUDOZKA_DB_URI}
-8
View File
@@ -1,8 +0,0 @@
{
"uid": "hudozka",
"append": true,
"watch": false,
"script": "index.js",
"sourceDir": "/home/hoster/www/art.shburg.org/out",
"wordingDir": "/home/hoster/www/art.shburg.org"
}
-58
View File
@@ -1,58 +0,0 @@
const gulp = require('gulp')
const postcss = require('gulp-postcss')
const sass = require('gulp-sass')
const imageMin = require('gulp-imagemin')
const concat = require('gulp-concat')
const autoprefixer = require('autoprefixer')
const cssnano = require('cssnano')
gulp.task('style', () => {
const processors = [
autoprefixer({
browsers: ['last 1 version']
}),
cssnano({
zindex: false
})
]
return gulp.src('./src/style/style.scss')
.pipe(sass())
.pipe(postcss(processors))
.pipe(concat('style.css'))
.pipe(gulp.dest('./public'))
})
gulp.task('copy fonts', () => {
return gulp.src('./src/assets/fonts/*/*')
.pipe(gulp.dest('./public/fonts'))
})
gulp.task('copy graphics', () => {
return gulp.src('./src/assets/graphics/*')
.pipe(gulp.dest('./public/graphics'))
})
gulp.task('copy 3rdparty', () => {
return gulp.src('./src/3rdparty/*')
.pipe(gulp.dest('./public'))
})
gulp.task('copy robots.txt', () => {
return gulp.src('./robots.txt')
.pipe(gulp.dest('./public'))
})
gulp.task('copy views', () => {
return gulp.src('./src/views/**')
.pipe(gulp.dest('./out/views'))
})
gulp.task('imagemin', () => {
return gulp.src('./src/assets/graphics/**/*')
.pipe(imageMin())
.pipe(gulp.dest('./public/graphics'))
})
gulp.task('copy', gulp.series('copy views', 'copy fonts', 'copy graphics', 'copy robots.txt', 'copy 3rdparty'))
gulp.task('default', gulp.series('style', 'copy', 'imagemin'))
-16
View File
@@ -1,16 +0,0 @@
#!/bin/sh
dir_path="$1"
build_file="$2"
app="hudozka"
script="forever.json"
cd ${dir_path}
gunzip -c ${build_file} | tar xopf -
#rm build.tar
npm install --production --loglevel error
echo "Deploying finish. Please restart hudozka.service manually"
-27
View File
@@ -1,27 +0,0 @@
FROM alpine:3.5
RUN apk add --no-cache python3 && \
apk add --no-cache py3-lxml && \
python3 -m ensurepip && \
rm -r /usr/lib/python*/ensurepip && \
pip3 install --upgrade pip setuptools && \
rm -r /root/.cache
LABEL maintainer "Roman Timashev <roman@tmshv.ru>"
ENV INSTALL_PATH /app
RUN mkdir -p $INSTALL_PATH
WORKDIR /$INSTALL_PATH
COPY requirements.txt .
RUN pip3 install -r requirements.txt
COPY app ./app
ENV DB_URI "mongodb://localhost:27017"
ENV DB_USER ""
ENV DB_PASSWORD ""
ENV DB_NAME "hudozka"
EXPOSE 5000
CMD python3 app/main.py
-10
View File
@@ -1,10 +0,0 @@
# Feed
Link to feed: [art.shlisselburg.org/feed](https://art.shlisselburg.org/feed)
## How to deploy with Docker
```bash
docker build -t hudozka/feed .
docker run -d --name hudozka-feed -p 18050:5000 -e DB_USER="<DB_USER>" -e DB_PASSWORD="<DB_PASSWORD>" -e DB_URI="<DB_URI>" hudozka/feed
```
-13
View File
@@ -1,13 +0,0 @@
from pymongo import MongoClient
from settings import db_uri, db_name, db_user, db_password
db = MongoClient(db_uri)[db_name]
if db_user and db_password:
auth_status = db.authenticate(db_user, db_password)
if not auth_status:
print('Failed to authenticate user')
exit(1)
def collection(name):
return db[name]
-39
View File
@@ -1,39 +0,0 @@
import html
from feedgen.feed import FeedGenerator
from db import collection
def get_items(collection_name, query={}):
return list(
collection(collection_name).find(query)
)
def get_feed():
events = get_items('events')
news = get_items('timeline', {'type': 'post'})
articles = sorted(events + news, key=lambda item: item['date'], reverse=True)
fg = FeedGenerator()
fg.id('art.shlisselburg.org')
fg.title('Шлиссельбургская ДХШ')
fg.link(href='https://art.shlisselburg.org', rel='alternate')
fg.logo('https://static.shlisselburg.org/art/graphics/favicon-144.png')
fg.link(href='https://art.shlisselburg.org/feed', rel='self')
fg.language('ru')
for article in articles:
content = html.unescape(article['post'])
article_id = article['id']
url = 'https://art.shlisselburg.org/article/{id}'.format(id=article_id)
fe = fg.add_entry()
fe.id(article_id)
fe.title(article['title'])
fe.content(content, None, 'CDATA')
fe.link({'href': url})
return fg.atom_str(pretty=True)
-5
View File
@@ -1,5 +0,0 @@
from server import app
from settings import host
if __name__ == '__main__':
app.run(host=host)
-14
View File
@@ -1,14 +0,0 @@
from flask import Flask
from feed import get_feed
app = Flask(__name__)
@app.route('/')
def root():
feed = get_feed()
if not feed:
return '', 404
return feed
-7
View File
@@ -1,7 +0,0 @@
import os
db_uri = os.getenv('DB_URI', 'mongodb://localhost:27017')
db_name = os.getenv('DB_NAME', 'hudozka')
db_user = os.getenv('DB_USER', None)
db_password = os.getenv('DB_PASSWORD', None)
host = os.getenv('APP_HOST', '0.0.0.0')
-5
View File
@@ -1,5 +0,0 @@
pymongo==3.4.0
Flask==0.12
redis==2.10.5
PyYAML==3.12
feedgen==0.5.1
+4
View File
@@ -0,0 +1,4 @@
.env
*.tar
node_modules
+3
View File
@@ -0,0 +1,3 @@
node_modules
.env
*.tar
+27
View File
@@ -0,0 +1,27 @@
# BUILD
FROM node:12-alpine as build
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
# Building app
RUN npm run build
# RUNTIME
FROM node:12-alpine
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm install --production
COPY --from=build /app/build ./build
EXPOSE 80
ENV PORT 80
ENV NODE_ENV production
# Running the app
CMD [ "npm", "start" ]
+755
View File
@@ -0,0 +1,755 @@
{
"name": "hudozka-api",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@types/body-parser": {
"version": "1.19.0",
"resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.0.tgz",
"integrity": "sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ==",
"dev": true,
"requires": {
"@types/connect": "*",
"@types/node": "*"
}
},
"@types/bson": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/@types/bson/-/bson-4.0.1.tgz",
"integrity": "sha512-K6VAEdLVJFBxKp8m5cRTbUfeZpuSvOuLKJLrgw9ANIXo00RiyGzgH4BKWWR4F520gV4tWmxG7q9sKQRVDuzrBw==",
"dev": true,
"requires": {
"@types/node": "*"
}
},
"@types/classnames": {
"version": "2.2.9",
"resolved": "https://registry.npmjs.org/@types/classnames/-/classnames-2.2.9.tgz",
"integrity": "sha512-MNl+rT5UmZeilaPxAVs6YaPC2m6aA8rofviZbhbxpPpl61uKodfdQVsBtgJGTqGizEf02oW3tsVe7FYB8kK14A==",
"dev": true
},
"@types/connect": {
"version": "3.4.33",
"resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.33.tgz",
"integrity": "sha512-2+FrkXY4zllzTNfJth7jOqEHC+enpLeGslEhpnTAkg21GkRrWV4SsAtqchtT4YS9/nODBU2/ZfsBY2X4J/dX7A==",
"dev": true,
"requires": {
"@types/node": "*"
}
},
"@types/express": {
"version": "4.17.2",
"resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.2.tgz",
"integrity": "sha512-5mHFNyavtLoJmnusB8OKJ5bshSzw+qkMIBAobLrIM48HJvunFva9mOa6aBwh64lBFyNwBbs0xiEFuj4eU/NjCA==",
"dev": true,
"requires": {
"@types/body-parser": "*",
"@types/express-serve-static-core": "*",
"@types/serve-static": "*"
}
},
"@types/express-serve-static-core": {
"version": "4.17.2",
"resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.2.tgz",
"integrity": "sha512-El9yMpctM6tORDAiBwZVLMcxoTMcqqRO9dVyYcn7ycLWbvR8klrDn8CAOwRfZujZtWD7yS/mshTdz43jMOejbg==",
"dev": true,
"requires": {
"@types/node": "*",
"@types/range-parser": "*"
}
},
"@types/mime": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.1.tgz",
"integrity": "sha512-FwI9gX75FgVBJ7ywgnq/P7tw+/o1GUbtP0KzbtusLigAOgIgNISRK0ZPl4qertvXSIE8YbsVJueQ90cDt9YYyw==",
"dev": true
},
"@types/mongodb": {
"version": "3.3.16",
"resolved": "https://registry.npmjs.org/@types/mongodb/-/mongodb-3.3.16.tgz",
"integrity": "sha512-i1Ov36BXdp+urtPsaSvrNfCdsaVn4Ukq1m1kGyzdWB1+eg3gJ68unXU5LNmnF4EAMRFY6FXZzA7/W3NST40b8g==",
"dev": true,
"requires": {
"@types/bson": "*",
"@types/node": "*"
}
},
"@types/node": {
"version": "13.7.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-13.7.1.tgz",
"integrity": "sha512-Zq8gcQGmn4txQEJeiXo/KiLpon8TzAl0kmKH4zdWctPj05nWwp1ClMdAVEloqrQKfaC48PNLdgN/aVaLqUrluA==",
"dev": true
},
"@types/range-parser": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz",
"integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==",
"dev": true
},
"@types/serve-static": {
"version": "1.13.3",
"resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.3.tgz",
"integrity": "sha512-oprSwp094zOglVrXdlo/4bAHtKTAxX6VT8FOZlBKrmyLbNvE1zxZyJ6yikMVtHIvwP45+ZQGJn+FdXGKTozq0g==",
"dev": true,
"requires": {
"@types/express-serve-static-core": "*",
"@types/mime": "*"
}
},
"accepts": {
"version": "1.3.7",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
"integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
"requires": {
"mime-types": "~2.1.24",
"negotiator": "0.6.2"
}
},
"arg": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
"integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
"dev": true
},
"array-flatten": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
"integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
},
"bl": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/bl/-/bl-2.2.0.tgz",
"integrity": "sha512-wbgvOpqopSr7uq6fJrLH8EsvYMJf9gzfo2jCsL2eTy75qXPukA4pCgHamOQkZtY5vmfVtjB+P3LNlMHW5CEZXA==",
"requires": {
"readable-stream": "^2.3.5",
"safe-buffer": "^5.1.1"
}
},
"body-parser": {
"version": "1.19.0",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",
"integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==",
"requires": {
"bytes": "3.1.0",
"content-type": "~1.0.4",
"debug": "2.6.9",
"depd": "~1.1.2",
"http-errors": "1.7.2",
"iconv-lite": "0.4.24",
"on-finished": "~2.3.0",
"qs": "6.7.0",
"raw-body": "2.4.0",
"type-is": "~1.6.17"
},
"dependencies": {
"bytes": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
"integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg=="
},
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"requires": {
"ms": "2.0.0"
}
},
"http-errors": {
"version": "1.7.2",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz",
"integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==",
"requires": {
"depd": "~1.1.2",
"inherits": "2.0.3",
"setprototypeof": "1.1.1",
"statuses": ">= 1.5.0 < 2",
"toidentifier": "1.0.0"
}
},
"iconv-lite": {
"version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
"requires": {
"safer-buffer": ">= 2.1.2 < 3"
}
},
"inherits": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
},
"raw-body": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz",
"integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==",
"requires": {
"bytes": "3.1.0",
"http-errors": "1.7.2",
"iconv-lite": "0.4.24",
"unpipe": "1.0.0"
}
}
}
},
"bson": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/bson/-/bson-1.1.3.tgz",
"integrity": "sha512-TdiJxMVnodVS7r0BdL42y/pqC9cL2iKynVwA0Ho3qbsQYr428veL3l7BQyuqiw+Q5SqqoT0m4srSY/BlZ9AxXg=="
},
"buffer-from": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
"dev": true
},
"content-disposition": {
"version": "0.5.3",
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz",
"integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==",
"requires": {
"safe-buffer": "5.1.2"
}
},
"content-type": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
"integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
},
"cookie": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz",
"integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg=="
},
"cookie-signature": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
"integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
},
"core-util-is": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
},
"denque": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/denque/-/denque-1.4.1.tgz",
"integrity": "sha512-OfzPuSZKGcgr96rf1oODnfjqBFmr1DVoc/TrItj3Ohe0Ah1C5WX5Baquw/9U9KovnQ88EqmJbD66rKYUQYN1tQ=="
},
"depd": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
"integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="
},
"destroy": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
"integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
},
"diff": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
"dev": true
},
"dotenv": {
"version": "8.2.0",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz",
"integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw=="
},
"ee-first": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
"integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
},
"encodeurl": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
"integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
},
"escape-html": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
"integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
},
"etag": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
"integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
},
"express": {
"version": "4.17.1",
"resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz",
"integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==",
"requires": {
"accepts": "~1.3.7",
"array-flatten": "1.1.1",
"body-parser": "1.19.0",
"content-disposition": "0.5.3",
"content-type": "~1.0.4",
"cookie": "0.4.0",
"cookie-signature": "1.0.6",
"debug": "2.6.9",
"depd": "~1.1.2",
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"etag": "~1.8.1",
"finalhandler": "~1.1.2",
"fresh": "0.5.2",
"merge-descriptors": "1.0.1",
"methods": "~1.1.2",
"on-finished": "~2.3.0",
"parseurl": "~1.3.3",
"path-to-regexp": "0.1.7",
"proxy-addr": "~2.0.5",
"qs": "6.7.0",
"range-parser": "~1.2.1",
"safe-buffer": "5.1.2",
"send": "0.17.1",
"serve-static": "1.14.1",
"setprototypeof": "1.1.1",
"statuses": "~1.5.0",
"type-is": "~1.6.18",
"utils-merge": "1.0.1",
"vary": "~1.1.2"
},
"dependencies": {
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"requires": {
"ms": "2.0.0"
}
},
"path-to-regexp": {
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
"integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
}
}
},
"feed": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/feed/-/feed-4.1.0.tgz",
"integrity": "sha512-dAXWXM8QMxZ1DRnAxDmy1MaWZFlh1Ku7TU3onbXgHrVJynsxkNGPUed1AxszVW8AXo43xExronVkIqK+ACsoBA==",
"requires": {
"xml-js": "^1.6.11"
}
},
"finalhandler": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
"integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==",
"requires": {
"debug": "2.6.9",
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"on-finished": "~2.3.0",
"parseurl": "~1.3.3",
"statuses": "~1.5.0",
"unpipe": "~1.0.0"
},
"dependencies": {
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"requires": {
"ms": "2.0.0"
}
}
}
},
"forwarded": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
"integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ="
},
"fresh": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
"integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
},
"http-errors": {
"version": "1.7.3",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz",
"integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==",
"requires": {
"depd": "~1.1.2",
"inherits": "2.0.4",
"setprototypeof": "1.1.1",
"statuses": ">= 1.5.0 < 2",
"toidentifier": "1.0.0"
}
},
"inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
"ipaddr.js": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.0.tgz",
"integrity": "sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA=="
},
"lodash": {
"version": "4.17.15",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A=="
},
"make-error": {
"version": "1.3.5",
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.5.tgz",
"integrity": "sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g==",
"dev": true
},
"media-typer": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
"integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
},
"memory-pager": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz",
"integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==",
"optional": true
},
"merge-descriptors": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
"integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
},
"methods": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
"integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
},
"mime": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
"integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
},
"mime-db": {
"version": "1.43.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz",
"integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ=="
},
"mime-types": {
"version": "2.1.26",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.26.tgz",
"integrity": "sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==",
"requires": {
"mime-db": "1.43.0"
}
},
"mongodb": {
"version": "3.5.3",
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.5.3.tgz",
"integrity": "sha512-II7P7A3XUdPiXRgcN96qIoRa1oesM6qLNZkzfPluNZjVkgQk3jnQwOT6/uDk4USRDTTLjNFw2vwfmbRGTA7msg==",
"requires": {
"bl": "^2.2.0",
"bson": "^1.1.1",
"denque": "^1.4.1",
"require_optional": "^1.0.1",
"safe-buffer": "^5.1.2",
"saslprep": "^1.0.0"
}
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
},
"negotiator": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
"integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw=="
},
"on-finished": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
"integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
"requires": {
"ee-first": "1.1.1"
}
},
"parseurl": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
"integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="
},
"process-nextick-args": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
},
"proxy-addr": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.5.tgz",
"integrity": "sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ==",
"requires": {
"forwarded": "~0.1.2",
"ipaddr.js": "1.9.0"
}
},
"qs": {
"version": "6.7.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
"integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ=="
},
"range-parser": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
"integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="
},
"readable-stream": {
"version": "2.3.7",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
"isarray": "~1.0.0",
"process-nextick-args": "~2.0.0",
"safe-buffer": "~5.1.1",
"string_decoder": "~1.1.1",
"util-deprecate": "~1.0.1"
},
"dependencies": {
"isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
}
}
},
"require_optional": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/require_optional/-/require_optional-1.0.1.tgz",
"integrity": "sha512-qhM/y57enGWHAe3v/NcwML6a3/vfESLe/sGM2dII+gEO0BpKRUkWZow/tyloNqJyN6kXSl3RyyM8Ll5D/sJP8g==",
"requires": {
"resolve-from": "^2.0.0",
"semver": "^5.1.0"
}
},
"resolve-from": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz",
"integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c="
},
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
},
"safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
"saslprep": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz",
"integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==",
"optional": true,
"requires": {
"sparse-bitfield": "^3.0.3"
}
},
"sax": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
},
"semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
},
"send": {
"version": "0.17.1",
"resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz",
"integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==",
"requires": {
"debug": "2.6.9",
"depd": "~1.1.2",
"destroy": "~1.0.4",
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"etag": "~1.8.1",
"fresh": "0.5.2",
"http-errors": "~1.7.2",
"mime": "1.6.0",
"ms": "2.1.1",
"on-finished": "~2.3.0",
"range-parser": "~1.2.1",
"statuses": "~1.5.0"
},
"dependencies": {
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"requires": {
"ms": "2.0.0"
},
"dependencies": {
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
}
}
},
"ms": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
"integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
}
}
},
"serve-static": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz",
"integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==",
"requires": {
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"parseurl": "~1.3.3",
"send": "0.17.1"
}
},
"setprototypeof": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
"integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw=="
},
"sitemap": {
"version": "1.13.0",
"resolved": "https://registry.npmjs.org/sitemap/-/sitemap-1.13.0.tgz",
"integrity": "sha1-Vpy+IYAgKSamKiZs094Jyc60P4M=",
"requires": {
"underscore": "^1.7.0",
"url-join": "^1.1.0"
}
},
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true
},
"source-map-support": {
"version": "0.5.16",
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.16.tgz",
"integrity": "sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ==",
"dev": true,
"requires": {
"buffer-from": "^1.0.0",
"source-map": "^0.6.0"
}
},
"sparse-bitfield": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz",
"integrity": "sha1-/0rm5oZWBWuks+eSqzM004JzyhE=",
"optional": true,
"requires": {
"memory-pager": "^1.0.2"
}
},
"statuses": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
"integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="
},
"string_decoder": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"requires": {
"safe-buffer": "~5.1.0"
}
},
"toidentifier": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
"integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw=="
},
"ts-node": {
"version": "8.6.2",
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.6.2.tgz",
"integrity": "sha512-4mZEbofxGqLL2RImpe3zMJukvEvcO1XP8bj8ozBPySdCUXEcU5cIRwR0aM3R+VoZq7iXc8N86NC0FspGRqP4gg==",
"dev": true,
"requires": {
"arg": "^4.1.0",
"diff": "^4.0.1",
"make-error": "^1.1.1",
"source-map-support": "^0.5.6",
"yn": "3.1.1"
}
},
"type-is": {
"version": "1.6.18",
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
"integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
"requires": {
"media-typer": "0.3.0",
"mime-types": "~2.1.24"
}
},
"typescript": {
"version": "3.7.5",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.7.5.tgz",
"integrity": "sha512-/P5lkRXkWHNAbcJIiHPfRoKqyd7bsyCma1hZNUGfn20qm64T6ZBlrzprymeu918H+mB/0rIg2gGK/BXkhhYgBw==",
"dev": true
},
"underscore": {
"version": "1.9.2",
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.9.2.tgz",
"integrity": "sha512-D39qtimx0c1fI3ya1Lnhk3E9nONswSKhnffBI0gME9C99fYOkNi04xs8K6pePLhvl1frbDemkaBQ5ikWllR2HQ=="
},
"unpipe": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
"integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
},
"url-join": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/url-join/-/url-join-1.1.0.tgz",
"integrity": "sha1-dBxsL0WWxIMNZxhGCSDQySIC3Hg="
},
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
},
"utils-merge": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
"integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
},
"vary": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
"integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
},
"xml-js": {
"version": "1.6.11",
"resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz",
"integrity": "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==",
"requires": {
"sax": "^1.2.4"
}
},
"yn": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
"integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
"dev": true
}
}
}
+36
View File
@@ -0,0 +1,36 @@
{
"name": "hudozka-api",
"private": true,
"version": "1.0.0",
"description": "",
"main": "src/server.ts",
"scripts": {
"start": "node build/server.js",
"dev": "ts-node src/server.ts",
"build": "tsc",
"sitemap": "node scripts/sitemap.js",
"feed": "node scripts/feed.js"
},
"repository": {
"type": "git",
"url": "https://github.com/tmshv/hudozka"
},
"author": "Roman Timashev",
"license": "ISC",
"dependencies": {
"dotenv": "^8.2.0",
"express": "^4.17.1",
"feed": "^4.0.0",
"lodash": "^4.17.15",
"mongodb": "^3.5.3",
"sitemap": "^1.5.0"
},
"devDependencies": {
"@types/classnames": "^2.2.9",
"@types/express": "^4.17.2",
"@types/mongodb": "^3.3.16",
"@types/node": "^13.7.1",
"ts-node": "^8.6.2",
"typescript": "^3.7.5"
}
}
@@ -0,0 +1,23 @@
import { getPathWaterfall } from '../lib/url'
import { Breadcrumb } from '../types'
import Page from '../core/Page'
export async function getItems(path: string): Promise<Breadcrumb> {
const bc = getPathWaterfall(path)
const parts = await Promise.all(bc.map(async href => {
const resource = await Page.findByUrl(href)
if (!resource) {
return null
}
const name = resource.title
return {
name,
href,
}
}))
return parts.filter(Boolean)
}
@@ -0,0 +1,51 @@
import { Request, Response } from 'express'
import Document from '../core/Document'
import { encodeFile } from '../factory/file'
export async function getItem(req: Request, res: Response) {
const id = req.params.slug
const document = await Document.findById(id)
if (document) {
res.json(encodeFile(document))
} else {
res.status(404)
res.json({
error: `Resource ${id} not found`
})
}
}
export async function getAll(req: Request, res: Response) {
const documents = await Document.find({ hidden: false })
if (documents) {
const items = documents
.map(encodeFile)
.filter(x => x.imageUrl) // skip documents without preview image; needs to be refactored
res.json({
items,
})
} else {
res.status(404)
res.json({
error: `Not found`
})
}
}
export async function getUrls(req: Request, res: Response) {
const data = await Document.find({})
if (data) {
const items = data.map(x => `/document/${x.id}`)
res.json({
items
})
} else {
res.status(404)
res.json({
error: `Not found`
})
}
}
@@ -0,0 +1,17 @@
import Image from '../core/Image'
import { encodeImage } from '../factory/image'
import { Request, Response } from 'express'
export async function getItem(req: Request, res: Response) {
const file = req.query.file
const image = await Image.findByFile(file)
if (image) {
res.json(encodeImage(image))
} else {
res.status(404)
res.json({
error: `Resource ${file} not found`
})
}
}
+117
View File
@@ -0,0 +1,117 @@
import { pick } from 'lodash'
import { Request, Response } from 'express'
import Page from '../core/Page'
import { dropTrailingSlash, readQueryArray, readQueryInt, readQueryString } from '../lib/url'
import { encodePage } from '../factory/page'
import * as breadcrumb from './breadcrumb'
import { isArrayOk } from '../lib/array'
function getSort(sortBy: string) {
if (!sortBy) {
return null
}
if (sortBy.charAt(0) === '-') {
const key = sortBy.substr(1, sortBy.length)
return {
[key]: -1,
}
}
return {
[sortBy]: 1,
}
}
async function resolveItem(page: Page) {
const breadcrumbs = await breadcrumb.getItems(page.getUrl())
page.setBreadcrumb(breadcrumbs)
return page
}
export async function getItem(req: Request, res: Response) {
const pageUrl = dropTrailingSlash(req.query.page)
const resource = await Page.findByUrl(pageUrl)
if (resource) {
const page = await resolveItem(resource)
res.json(encodePage(page))
} else {
res.status(404)
res.json({
error: `Resource ${pageUrl} not found`
})
}
}
export async function getAll(req: Request, res: Response) {
const items = await Page.find({})
if (items) {
res.json({
items,
})
} else {
res.status(404)
res.json({
error: `Not found`
})
}
}
export async function getByTags(req: Request, res: Response) {
const skip = readQueryInt(req, 'skip')
const limit = readQueryInt(req, 'limit')
const sortBy = readQueryString(req, 'sortBy')
const sort = getSort(sortBy)
const fields = readQueryArray(req, 'field')
const tags = readQueryArray(req, 'tag')
if (tags.length === 0) {
res.status(400)
return res.json({
error: `No tags in request`
})
}
const options = { skip, limit, sort }
const models = await Page.find({
tags: { $in: tags },
}, options)
if (models) {
const pages = await Promise.all(models.map(resolveItem))
const encodedItems = pages.map(encodePage)
const items = isArrayOk(fields)
? encodedItems.map(x => pick(x, fields))
: encodedItems
res.json({
items,
})
} else {
res.status(404)
res.json({
error: `Not found`
})
}
}
export async function getUrls(req: Request, res: Response) {
const data = await Page.find({})
if (data) {
const items = data.map(x => x.url)
res.json({
items,
})
} else {
res.status(404)
res.json({
error: `Not found`
})
}
}
@@ -0,0 +1,22 @@
import Page from '../core/Page'
import { Request, Response } from 'express'
import { unique } from '../lib/array'
export async function getAll(req: Request, res: Response) {
const data = await Page.find({})
const tags = data
.flatMap(x => x.tags)
.filter(x => x.isValid())
const items = unique(tags, t => t.slug)
if (data) {
res.json({
items,
})
} else {
res.status(404)
res.json({
error: `Not found`
})
}
}
+18
View File
@@ -0,0 +1,18 @@
import { Collection } from 'mongodb'
import * as db from '../db'
const store = new Map<string, Collection>()
export default class Data {
static setStore(key: string, collection: Collection) {
store.set(key, collection)
}
static getStore<T>(key: string): Collection<T> {
return store.get(key)
}
static getCollection(name: string): Collection {
return db.collection(name)
}
}
+68
View File
@@ -0,0 +1,68 @@
import Data from './Data'
import Image from './Image'
import { find, findOne } from '../lib/store'
const store = () => Data.getStore('Document')
export default class Document {
static async find(query, options = {}): Promise<Document[]> {
const items = await find(store(), query, options as any)
return Promise.all(items.map(processDocument))
}
static async findById(id) {
const data = await findOne(store(), { id })
if (!data) return null
return processDocument(data)
}
public id: any
public hash: any
public file: any
public fileInfo: any
public type: any
public title: any
public category: any
public url: any
public preview: any
public viewUrl: any
constructor(data) {
this.id = data.id
this.hash = data.hash
this.file = data.file
// In the future: use fileInfo only
this.fileInfo = data.fileInfo
? new DocumentFile(data.fileInfo)
: new DocumentFile(data.file)
this.type = data.type
this.title = data.title
this.category = data.category
this.url = data.url
this.preview = data.preview
this.viewUrl = `/document/${this.id}`
}
}
class DocumentFile {
public name: any
public size: any
constructor(data) {
this.name = data.name
this.size = data.size
}
}
const processDocument = async data => {
const imageId = data.preview
const preview = await Image.findById(imageId)
return new Document({
...data,
preview,
})
}
+105
View File
@@ -0,0 +1,105 @@
import Data from './Data'
import ImageArtifactType from './ImageArtifactType'
import { findOne } from '../lib/store'
import { ObjectId } from 'mongodb'
/**
*
* {a: {}, b: {}, ...} -> Map (a: Class, b: Class)
*
* @param Class
* @param object
*/
function mapOf(Class, object) {
return Object
.entries(object)
.reduce((map, i) => (
map.set(i[0], new Class(i[1]))
), new Map())
}
const store = () => Data.getStore('Image')
export default class Image {
static async findById(id: ObjectId) {
const data = await findOne(store(), { _id: id })
if (!data) return null
const artifacts = data.data
return new Image({ ...data, artifacts })
}
static async findByFile(file: string) {
const data = await findOne(store(), { file })
if (!data) return null
const artifacts = data.data
return new Image({ ...data, artifacts })
}
public hash: string
public file: string
public artifacts: Map<string, ImageArtifact>
constructor({ hash, file, artifacts }) {
this.hash = hash
this.file = file
this.artifacts = mapOf(ImageArtifact, artifacts)
}
getArtifact(size) {
return this.artifacts.get(size)
}
findArtifact(sizes) {
for (let size of sizes) {
const a = this.getArtifact(size)
if (a) return a
}
return null
}
getPicture(size) {
const retinaSize = ImageArtifactType.retina(size)
const a = this.getArtifact(size)
const a2 = this.getArtifact(retinaSize)
const srcset = !a2
? []
: [{
url: a2.url,
density: ImageArtifactType.RETINA_DENSITY,
}]
return {
src: a.url,
width: a.width,
height: a.height,
set: srcset,
}
}
getSrc(): string | null {
const a = this.getArtifact(ImageArtifactType.ORIGINAL)
if (!a) {
return null
}
return a.url
}
}
class ImageArtifact {
public url: string
public size: string
public width: number
public height: number
constructor({ url, size, width, height }) {
this.url = url
this.size = size
this.width = width
this.height = height
}
}
+113
View File
@@ -0,0 +1,113 @@
import Data from './Data'
import { find as storeFind, findOne, total } from '../lib/store'
import Image from './Image'
import { Tag } from './Tag'
import { ObjectId } from 'mongodb'
import { Breadcrumb } from '../types'
const store = () => Data.getStore('Page')
type PageDto = {
[name: string]: any
preview?: ObjectId
images: ObjectId[]
}
export default class Page {
static async find(query, options = {}): Promise<Page[]> {
const items = await storeFind(store(), query, options as any)
return Promise.all(items.map(processPage))
}
static async findById(id) {
const item = await findOne(store(), { id })
return !item
? null
: processPage(item)
}
static async findByUrl(url: string) {
const item = await findOne(store(), { url })
return !item
? null
: processPage(item)
}
static async total(query = {}) {
return total(store(), query)
}
public id: any
public hash: any
public file: any
public url: string
public content: any
public title: any
public date: Date
public tags: Tag[]
public data: any
public images: ObjectId[]
public documents: any
public preview?: Image
public tokens: any[]
public description: string
public featured: boolean
private breadcrumb: Breadcrumb
constructor(data: { [name: string]: any }) {
this.id = data.id
this.hash = data.hash
this.file = data.file
this.url = data.url
this.content = data.content
this.title = data.title
this.data = data.data
this.date = data.date
this.images = data.images
this.documents = data.documents
this.preview = data.preview
this.tokens = data.tokens
this.tags = (data.tags || []).map((x: string) => new Tag(x, x))
this.featured = data.featured
this.description = data.description
}
public setBreadcrumb(value: Breadcrumb) {
this.breadcrumb = value
return this
}
public getBreadcrumb() {
return this.breadcrumb
}
public getUrl() {
return this.url
}
}
function firstItem<T>(items: T[] = []): T {
return items.length
? items[0]
: null
}
async function processPage(item: PageDto): Promise<Page> {
let preview: Image = null
const previewId = item.preview
? item.preview
: firstItem(item.images)
if (previewId) {
preview = await Image.findById(previewId)
}
return new Page({
...item,
preview,
})
}
+23
View File
@@ -0,0 +1,23 @@
import { translit } from '../lib/translit'
export class Tag {
public static fromCyrillic(tag: string) {
const slug = tag
? translit(tag).toLowerCase()
: tag
return new Tag(tag, slug)
}
public name: string
public slug: string
constructor(name: string, slug: string) {
this.name = name
this.slug = slug
}
public isValid() {
return !!this.slug
}
}
+35
View File
@@ -0,0 +1,35 @@
import Data from './core/Data'
import { MongoClient, ObjectId, Db } from 'mongodb'
var db: Db
export async function connect(dbName: string, mongoUri: string) {
if (db) {
return db
}
const connection = await MongoClient.connect(mongoUri, { useUnifiedTopology: true })
db = init(connection.db(dbName))
return db
}
export function collection(name) {
return db.collection(name)
}
export function id(i) {
if (typeof i === 'string') return new ObjectId(i)
else if (i instanceof ObjectId) return i
else if (i instanceof Object) return '_id' in i ? new ObjectId(i._id) : null
return null
}
function init(db: Db) {
console.log('INIT DB')
Data.setStore('Page', db.collection('pages'))
Data.setStore('Image', db.collection('images'))
Data.setStore('Document', db.collection('documents'))
Data.setStore('Settings', db.collection('settings'))
return db
}
+35
View File
@@ -0,0 +1,35 @@
import ImageArtifactType from '../core/ImageArtifactType'
const sizes = [
ImageArtifactType.MEDIUM,
ImageArtifactType.BIG,
ImageArtifactType.ORIGIN,
]
export function encodeFilePreview(file, sizes) {
const preview = file.preview
if (!preview) return null
const image = preview.findArtifact(sizes)
if (!image) return null
return image.url
}
export function encodeFile(file) {
const imageUrl = encodeFilePreview(file, sizes)
const category = (file.category || '')
.replace('Documents/', '')
.replace('Pages/', '')
.replace('Articles /', '')
return {
imageUrl,
category,
title: file.title,
fileName: file.fileInfo.name,
fileSize: file.fileInfo.size,
fileUrl: file.url,
url: file.viewUrl,
}
}
+48
View File
@@ -0,0 +1,48 @@
import ImageArtifactType from '../core/ImageArtifactType'
import Image from '../core/Image'
export type ImageArtifactDto = {
height: number
width: number
src: string
set: Array<{
density: number
url: string
}>
}
export type ImageDto = {
artifacts: {
original: ImageArtifactDto,
large: ImageArtifactDto,
big: ImageArtifactDto,
medium: ImageArtifactDto,
small: ImageArtifactDto,
fb: ImageArtifactDto,
},
hash: string
file: string
}
export function encodeImage(image: Image): ImageDto {
const artifacts = [
ImageArtifactType.SMALL,
ImageArtifactType.MEDIUM,
ImageArtifactType.BIG,
ImageArtifactType.LARGE,
ImageArtifactType.ORIGIN,
ImageArtifactType.ORIGINAL,
ImageArtifactType.FACEBOOK = 'fb'
].reduce((acc, size) => {
return {
...acc,
[size]: image.getPicture(size),
}
}, {})
return {
artifacts: artifacts as any,
hash: image.hash,
file: image.file,
}
}
+47
View File
@@ -0,0 +1,47 @@
import { encodeImage, ImageDto } from './image'
import Page from '../core/Page'
import { Breadcrumb } from '../types'
import { Tag } from '../core/Tag'
type Token = {
token: string
data: any
}
type PageDto = {
id: string
title: string
date?: string
url: string
data: string
description: string
preview?: ImageDto
tokens: Token[]
tags: Tag[]
featured: boolean
breadcrumb: Breadcrumb
coverSrc?: string
}
export function encodePage(page: Page): PageDto {
const preview = page.preview ? encodeImage(page.preview) : null
const date = page.date ? page.date.toString() : null
const breadcrumb = page.getBreadcrumb()
const coverSrc = page.preview ? page.preview.getSrc() : null
return {
id: page.id,
title: page.title,
url: page.url,
data: page.data,
description: page.description,
tokens: page.tokens,
tags: page.tags,
featured: page.featured,
preview,
date,
breadcrumb,
coverSrc,
}
}
+31
View File
@@ -0,0 +1,31 @@
export function unique<T>(items: T[], key: (item: T) => string): T[] {
const map = new Map(items.map(x => [key(x), x]))
return [...map.values()]
}
export function ensureArray<T>(value: T | T[]): T[] {
if (!value) {
return []
}
if (Array.isArray(value)) {
return value
}
return [value]
}
/**
*
* Check if array has one item at least
*
* @param items
*/
export function isArrayOk<T>(items: T[]): boolean {
if (!Array.isArray(items)) {
return false
}
return items.length > 0
}
+19
View File
@@ -0,0 +1,19 @@
export async function find(collection, query, { sort, skip, limit }) {
const cursor = collection.find(query)
if (sort) cursor.sort(sort)
if (skip) cursor.skip(skip)
if (limit) cursor.limit(limit)
return cursor.toArray()
}
export async function findOne(collection, query) {
return collection.findOne(query)
}
export async function total(collection, query) {
return collection
.find(query)
.count()
}
+80
View File
@@ -0,0 +1,80 @@
const map = new Map<string, string>([
['', '_'],
['А', 'A'],
['а', 'a'],
['Б', 'B'],
['б', 'b'],
['В', 'V'],
['в', 'v'],
['Г', 'G'],
['г', 'g'],
['Д', 'D'],
['д', 'd'],
['Е', 'E'],
['е', 'e'],
['Ё', 'E'],
['ё', 'e'],
['Ж', 'Zh'],
['ж', 'zh'],
['З', 'Z'],
['з', 'z'],
['И', 'I'],
['и', 'i'],
['Й', 'Y'],
['й', 'y'],
['К', 'K'],
['к', 'k'],
['Л', 'L'],
['л', 'l'],
['М', 'M'],
['м', 'm'],
['Н', 'N'],
['н', 'n'],
['О', 'O'],
['о', 'o'],
['П', 'P'],
['п', 'p'],
['Р', 'R'],
['р', 'r'],
['С', 'S'],
['с', 's'],
['Т', 'T'],
['т', 't'],
['У', 'U'],
['у', 'u'],
['Ф', 'F'],
['ф', 'f'],
['Х', 'Kh'],
['х', 'kh'],
['Ц', 'Ts'],
['ц', 'ts'],
['Ч', 'Ch'],
['ч', 'ch'],
['Ш', 'Sh'],
['ш', 'sh'],
['Щ', 'Sch'],
['щ', 'sch'],
['ь', ''],
['Ы', 'Y'],
['ы', 'y'],
['ъ', ''],
['Э', 'E'],
['э', 'e'],
['Ю', 'Yu'],
['ю', 'yu'],
['Я', 'Ya'],
['я', 'ya'],
])
export function translit(sample: string): string {
return [...sample]
.map(char => {
if (map.has(char)) {
return map.get(char)
}
return ''
})
.join('')
}
+48
View File
@@ -0,0 +1,48 @@
import { Request } from 'express'
import { ensureArray } from './array'
export function dropTrailingSlash(path: string) {
if (path === '/' || path === '') {
return '/'
}
const lastChar = path.charAt(path.length - 1)
if (lastChar === '/') {
return path.substr(0, path.length - 1)
}
return path
}
export function getPathWaterfall(path: string): string[] {
const parts = path
.split('/')
.filter(Boolean)
.reduce((acc, part, index, parts) => {
const i = index + 1
const item = `/${parts.slice(0, i).join('/')}`
return [
...acc,
item
]
}, [])
return ['/', ...parts]
}
export function readQueryInt(req: Request, key: string) {
const int = (value: string | string[]) => parseInt(Array.isArray(value)
? value[0]
: value
)
return int(req.query[key]) || 0
}
export function readQueryString(req: Request, key: string) {
return `${req.query[key]}`
}
export function readQueryArray(req: Request, key: string) {
return ensureArray(req.query[key])
}
+43
View File
@@ -0,0 +1,43 @@
import { config } from 'dotenv'
import express from 'express'
import { connect } from './db'
import * as file from './controllers/file'
import * as page from './controllers/page'
import * as image from './controllers/image'
import * as tag from './controllers/tag'
async function main() {
const port = process.env.PORT || '3000'
const mongoUri = process.env.MONGO_URI
try {
await connect('hudozka', mongoUri)
console.log('connected')
} catch (e) {
console.error(e.message)
process.exit(1)
}
const app = express()
app.get('/files', file.getAll)
app.get('/files/urls', file.getUrls)
app.get('/files/:slug', file.getItem)
app.get('/pages', page.getAll)
app.get('/pages/urls', page.getUrls)
app.get('/pages/tags', page.getByTags)
app.get('/page', page.getItem)
app.get('/image', image.getItem)
app.get('/tags', tag.getAll)
app.listen(port, () => {
console.log(`> Ready on http://localhost:${port}`)
})
}
config()
main()
+6
View File
@@ -0,0 +1,6 @@
export type BreadcrumbPart = {
name: string
href: string
}
export type Breadcrumb = BreadcrumbPart[]
+23
View File
@@ -0,0 +1,23 @@
{
"compilerOptions": {
"outDir": "./build",
"target": "esnext",
"lib": [
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"strict": false,
"forceConsistentCasingInFileNames": true,
"esModuleInterop": true,
"module": "commonjs",
"moduleResolution": "node",
"resolveJsonModule": true
},
"exclude": [
"node_modules"
],
"include": [
"**/*.ts"
]
}
@@ -1,6 +1,6 @@
## Usage
Sync Hudozka
Sync tool
```bash
<ENV> python3 sync.py
```
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -10,10 +10,14 @@ class DocumentToken(Token):
super().__init__(name='file', data=data)
self.joinable = False
self.build = None
async def compile(self):
async def get_data(self):
data = parse_file(self.data)
document = await self.build(data)
return document
async def compile(self):
document = await self.get_data()
return create_document(document)
File renamed without changes.
@@ -16,12 +16,15 @@ class Marker:
def add_tree_middleware(self, callback):
self.tree_middlewares.append(callback)
async def create_tree(self, text: str):
def parse(self, text: str):
tokens = text.split('\n')
tokens = self.markup_tokens(tokens)
tokens = join_tokens(tokens)
tokens = merge_tokens(tokens)
return tokens
async def create_tree(self, tokens: list):
compiled = await compile_tokens(tokens)
tree = lxml.html.fromstring(compiled)
return await self.process_tree(tree)
@@ -102,17 +105,8 @@ async def compile_tokens(tokens: list):
return '\n'.join(result)
def extract_files(text: str) -> [str]:
html = markdown(text)
post_html = lxml.html.fromstring(html)
images = post_html.cssselect('img')
images = [img.get('src') for img in images]
return images, []
def html_from_tree(tree):
html = lxml.html.tostring(tree, encoding='unicode')
return html
@@ -38,8 +38,12 @@ class Token:
self.data = data
self.joinable = True
async def compile(self):
return str(self.data)
async def get_data(self):
return self.data
async def compile(self) -> str:
data = await self.get_data()
return str(data)
def merge(self, token):
return self
@@ -73,7 +77,8 @@ class TextToken(Token):
return TextToken(data.strip())
async def compile(self):
return markdown_to_html(self.data)
data = await self.get_data()
return markdown_to_html(data)
class FileToken(Token):
@@ -85,8 +90,11 @@ class FileToken(Token):
super().__init__(name='file', data=data)
self.joinable = False
async def get_data(self):
return parse_file(self.data)
async def compile(self):
data = parse_file(self.data)
data = await self.get_data()
url = data['file']
text = data['caption'] if data['caption'] else url
return f'<a href="{url}">{text}</a>'
@@ -99,7 +107,7 @@ class ImageToken(Token):
def __init__(self, data) -> None:
super().__init__(name='image', data=data)
self.joinable = True
self.joinable = False
self.build = None
def merge(self, token: Token):
@@ -107,9 +115,13 @@ class ImageToken(Token):
merged_token.build = self.build
return merged_token
async def get_data(self):
data = parse_file(self.data)
data = await self.build(data)
return data
async def compile(self):
img = self.parse_data()
img = await self.build(img)
img = await self.get_data()
alt = img['alt']
caption = markdown_to_html(img['caption'])
src = img['src']
@@ -124,9 +136,6 @@ class ImageToken(Token):
'''
return tpl.format(img).strip()
def parse_data(self):
return parse_file(self.data)
class ImageCollectionToken(ImageToken):
def __init__(self, data) -> None:
@@ -143,13 +152,16 @@ class ImageCollectionToken(ImageToken):
merged_token.build = self.build
return merged_token
async def compile(self):
data = self.parse_data()
async def get_data(self):
items = [parse_file(x) for x in self.data]
images = []
for x in data:
for x in items:
img = await self.build(x)
images.append(img)
return images
async def compile(self):
images = await self.get_data()
images = [x['src'] for x in images]
images = [f'<img src="{x}">' for x in images]
images = '\n'.join(images)
@@ -165,10 +177,6 @@ class ImageCollectionToken(ImageToken):
</div>
'''
def parse_data(self):
return [parse_file(x) for x in self.data]
class UrlToken(Token):
@staticmethod
def test(data: str):
File renamed without changes.
+34
View File
@@ -0,0 +1,34 @@
import lxml.html
import re
from markdown import markdown
from kazimir.figure import FigureExtension
from kazimir.instagram import InstagramExtension
from sync.data import request
def extract_files(text: str) -> [str]:
html = markdown(text)
post_html = lxml.html.fromstring(html)
images = post_html.cssselect('img')
images = [img.get('src') for img in images]
return images, []
def html_from_tree(tree):
html = lxml.html.tostring(tree, encoding='unicode')
return html
async def typo(text):
from kazimir import artlebedev
result = await artlebedev.typograf(text)
if result == 'Размер текста ограничен 32 КБ':
return text
return result
# url = 'http://www.typograf.ru/webservice/'
# params = dict(text=text)
# return await request.post(url, params, {'chr': 'utf-8'})
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -1,12 +1,12 @@
cssselect==0.9.2
lxml==3.6.1
Markdown==2.6.6
Pillow==3.3.0
Pillow==6.2.0
pymongo==3.3.0
PyPDF2==1.26.0
python-frontmatter==0.3.1
PyYAML==3.11
requests==2.10.0
PyYAML==5.1
requests==2.20.0
six==1.10.0
smartcrop==0.1
toml==0.9.2
@@ -41,26 +41,8 @@ database_uri = value('database_uri') # env('MONGO_URI')
skip_unchanged = value('skip_unchanged')
person_uri = {
'Н.В.Андреева': 'nv-andreeva',
'И.Н.Втюрина': 'in-vturina',
'О.Д.Гоголева': 'od-gogoleva',
'В.А.Саржин': 'va-sarzhin',
'Р.К.Тимашев': 'rk-timashev',
'А.С.Тимашева': 'as-timasheva',
}
upload_enabled = value('upload_enabled')
upload_url_image = 'https://static.shlisselburg.org/upload/art/images/{}'
upload_auth = (
value('upload_auth')['login'],
value('upload_auth')['password'],
)
image_processing_enabled = value('image_processing')
album_html_img_class = 'hudozka-product'
image_ext = '.jpg'
image_sizes = [
('original', None, None),
@@ -92,60 +74,33 @@ date_formats = [
'%d.%m.%Y %H:%M:%S'
]
date_formats_direct = [
'%Y',
'%m.%Y',
'%d.%m.%Y',
]
date_formats_reverse = [
'%Y',
'%Y.%m',
'%Y.%m.%d'
]
origin = value('origin')
collection_settings = 'settings'
collection_images = 'images'
collection_documents = 'documents'
collection_schedules = 'schedules'
collection_articles = 'articles'
collection_collective = 'collective'
collection_albums = 'albums'
collection_pages = 'pages'
hash_salt_articles = '5'
hash_salt_pages = '2'
hash_salt_albums = '0'
hash_salt_documents = '1'
hash_salt_images = '1'
hash_salt_person = '2'
hash_salt_pages = '4'
hash_salt_documents = '4'
hash_salt_images = '5'
provider_name = value('provider')['name'] # env('SYNC_PROVIDER', 'fs')
provider_root = value('provider')['root'] # env('SYNC_PROVIDER', 'fs')
f = abs_fn(provider_root)
dir_settings = './Settings'
dir_documents = './Documents'
dir_schedules = './Schedules'
dir_articles = './Articles'
dir_persons = './Collective'
dir_albums = './Gallery'
dir_pages = './Pages'
dir_images = './Images'
document_url_template = 'https://static.shlisselburg.org/art/uploads/{file}'
document_url_upload_template = 'https://static.shlisselburg.org/upload/art/uploads/{file}'
document_url_preview_template = 'https://static.shlisselburg.org/art/images/{id}-{size}{ext}'
image_url_upload = 'https://static.shlisselburg.org/upload/art/images/'
image_url_base = 'https://static.shlisselburg.org/art/images/'
person_image_url_template = 'https://static.shlisselburg.org/art/images/person-{id}-{size}{ext}'
yandex_disk_access_token = value('yandex_disk_access_token') # env('YANDEX_DISK_ACCESS_TOKEN')
update_enabled = value('update_enabled')
delete_enabled = value('delete_enabled')
auth_s3 = {
'region_name': 'ams3',
'endpoint_url': 'https://dir.ams3.digitaloceanspaces.com',
'aws_access_key_id': value('s3')['client_id'],
'aws_secret_access_key': value('s3')['client_secret'],
}
+50
View File
@@ -0,0 +1,50 @@
import settings
from sync.data.fs import FSProvider
from sync.data.yandexdisk import YDProvider
import asyncio
async def run_check(run_interval=0):
run_interval = 1
from yandexdisk import YDClient
client = YDClient(settings.yandex_disk_access_token)
async def need_to_update():
res = client.last_uploaded()
items = res['items']
paths = [i['path'] for i in items]
for i in paths:
if i.startswith('disk:/Hudozka/Site'):
return True
return False
while True:
status = await need_to_update()
if status:
print('DO SYNC')
# await run(0)
if run_interval == 0:
break
else:
await asyncio.sleep(run_interval)
def get_provider(provider_type, root):
if provider_type == 'fs':
return FSProvider(root)
elif provider_type == 'yd':
return YDProvider(root, settings.yandex_disk_access_token)
return None
if __name__ == '__main__':
interval = settings.interval
loop = asyncio.get_event_loop()
loop.run_until_complete(run_check(interval))
loop.close()
+75
View File
@@ -0,0 +1,75 @@
import settings
from sync.core import Sync
from sync.data.fs import FSProvider
from sync.data.yandexdisk import YDProvider
import asyncio
import logging
from sync.models.Page import Page, PageController
def init_logger(name: str, file: str):
logger = logging.getLogger(name)
logger.setLevel(logging.DEBUG)
# create file handler which logs even debug messages
fh = logging.FileHandler(file)
fh.setLevel(logging.DEBUG)
# create console handler with a higher log level
ch = logging.StreamHandler()
# ch.setLevel(logging.ERROR)
ch.setLevel(logging.DEBUG)
# create formatter and add it to the handlers
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
fh.setFormatter(formatter)
ch.setFormatter(formatter)
# add the handlers to the logger
logger.addHandler(fh)
logger.addHandler(ch)
async def run_sync(sync: Sync, **kwargs):
await sync.run(**kwargs)
async def run(run_interval=0):
provider = get_provider(settings.provider_name, settings.provider_root)
controller = PageController(provider)
sync_pages = Sync(
ctrl=controller,
name='Page'
)
sync_pages.set_options(True, True, True)
while True:
await asyncio.wait([
run_sync(sync_pages),
])
if run_interval == 0:
break
else:
await asyncio.sleep(run_interval)
def get_provider(provider_type, root):
if provider_type == 'fs':
return FSProvider(root)
elif provider_type == 'yd':
return YDProvider(root, settings.yandex_disk_access_token)
return None
if __name__ == '__main__':
init_logger(settings.name, 'hudozka.log')
interval = settings.interval
loop = asyncio.get_event_loop()
loop.run_until_complete(run(interval))
loop.close()
@@ -3,8 +3,6 @@ import re
from datetime import datetime
import lxml.html
from markdown import markdown
import kazimir
import settings
from kazimir.CSVToken import CSVToken
@@ -47,12 +45,6 @@ def create_date(date_str, date_formats=None):
return None
# 2016 На крыльях бабочек
# 2016.10 На крыльях бабочек
# 2016.10.10 На крыльях бабочек
folder_name_pattern = re.compile('([\d.]+)(.*)')
async def untouched(items: [Model]) -> [Model]:
if settings.skip_unchanged:
return items
@@ -75,21 +67,6 @@ async def untouched(items: [Model]) -> [Model]:
# return filtered_documents
def create_date_and_title_from_folder_name(folder_name, date_formats=None):
m = folder_name_pattern.findall(folder_name)
if not m:
return None, None
date_str, title = m[0]
title = os.path.splitext(title.strip())[0]
date = create_date(date_str, date_formats)
if not date:
return None, title
return date, title
async def create_post(provider: Provider, folder: str, md: str, sizes):
from kazimir.fix_links_quotes import fix_links_quotes
@@ -155,25 +132,22 @@ async def create_post(provider: Provider, folder: str, md: str, sizes):
# m.add_token_factory(TokenFactory(FileToken))
m.add_token_factory(TokenFactory(TextToken))
m.add_tree_middleware(fix_links_quotes)
html = await m.create_tree(md)
post = kazimir.html_from_tree(html)
tokens = m.parse(md)
tree = await m.create_tree(tokens)
post = kazimir.html_from_tree(tree)
post = await kazimir.typo(post)
return post, images, documents
encoded_tokens = []
for t in tokens:
data = await t.get_data()
encoded_tokens.append({
'token': t.name,
'data': data,
})
def images_from_html(md):
if not md:
return []
post_html = lxml.html.fromstring(md)
images = []
for img in post_html.cssselect('img'):
src = img.get('src')
images.append(src)
return images
return post, images, documents, encoded_tokens
def title_from_html(md):
@@ -181,11 +155,3 @@ def title_from_html(md):
titles = html.cssselect('h1')
if len(titles):
return titles[0].text
create_post_from_image_list = lambda images: markdown(
'\n'.join(map(
lambda i: '![]({img})'.format(img=i),
images
))
)
@@ -1,19 +1,10 @@
import logging
import settings
from sync import untouched
from sync.data import Provider
def get_id(item):
try:
return item.id
except AttributeError:
return item['id']
class Sync:
def __init__(self, provider: Provider, model):
def __init__(self, ctrl, name: str):
super().__init__()
self.validate_urls = True
@@ -23,21 +14,34 @@ class Sync:
}
self.__delete_query = lambda item: {'_id': item['_id']}
name = model.__name__
self.logger = logging.getLogger('%s.%s' % (settings.name, name))
self.provider = provider
self.model = model
self.ctrl = ctrl
self.filter_item_fn = lambda x: True
async def clean(self):
pass
self.skip_unchanged = True
self.update_enabled = True
self.delete_enabled = True
def set_options(self, su: bool, u: bool, d: bool):
self.skip_unchanged = su
self.update_enabled = u
self.delete_enabled = d
return self
def set_item_filter(self, fn):
self.filter_item_fn = fn
return self
async def build(self, item):
args = self._get_build_args()
await item.build(**args)
return item
async def update(self, item):
args = self._get_build_args()
await item.build(**args)
await item.upload()
await item.save()
return item
def _get_build_args(self):
return {
@@ -72,32 +76,43 @@ class Sync:
"""
self.logger.info('Checking for update')
items = await self.model.scan(self.provider)
items = await self.ctrl.get_items()
self.logger.info('Found {} Item(s)'.format(len(items)))
all_items = items
if self.validate_urls:
self.check_urls_uniqueness(items)
self.check_urls_uniqueness(all_items)
# SKIP UNTOUCHED DOCUMENTS
changed_items = await untouched(items)
self.logger.info('Changed {} Items(s)'.format(len(changed_items)))
if self.skip_unchanged:
items = await untouched(all_items)
# Optionally trim list of models by custom filter
items = [
x
for x in items
if self.filter_item_fn(x)
]
self.logger.info(f'Ready to process {len(items)} item(s)')
# BUILDING
for item in items:
self.logger.info(f'Build Item {item}')
await self.build(item)
# UPDATING
if settings.update_enabled:
for item in changed_items:
if self.update_enabled:
for item in items:
await self.update(item)
self.logger.info('Updated Item {}'.format(item))
# DELETING
if settings.delete_enabled:
obsolete_items = await self.model.find(self.__items_to_delete_query(items))
obsolete_items = list(obsolete_items)
if self.delete_enabled:
obsolete_items = await self.ctrl.find(self.__items_to_delete_query(all_items))
for item in obsolete_items:
self.logger.info('Deleting Item {}'.format(item['id']))
await self.model.delete(self.__delete_query(item))
await self.clean()
await self.ctrl.delete_item(self.__delete_query(item))
def check_urls_uniqueness(self, items):
urls = [x.url for x in items]
@@ -106,6 +121,3 @@ class Sync:
if len(urls) != len(unique_urls):
self.logger.error('URLs is not unique')
raise Exception('URLs is not unique')
async def upload(self):
pass
File renamed without changes.
File renamed without changes.
+40
View File
@@ -0,0 +1,40 @@
import aiohttp
from boto3 import session
from mimetypes import MimeTypes
import logging
import settings
logger = logging.getLogger(settings.name + '.S3')
async def s3_put(obj, path):
"""
:param obj: uploads/file.pdf
:param path: to/to/local/file.pdf
:return:
"""
logger.info('Put {}'.format(obj))
s = session.Session()
client = s.client('s3', **settings.auth_s3)
mime = MimeTypes()
mime_type, enc = mime.guess_type(path)
# Upload a file to your Space
client.upload_file(path, 'hudozka', obj, ExtraArgs={
'ACL': 'public-read',
'ContentType': mime_type,
})
async def get(url):
async with aiohttp.ClientSession as aio_session:
res = aio_session.get(url)
return await res.text()
async def post(url, data, params={}, headers={}):
async with aiohttp.ClientSession() as aio_session:
async with aio_session.post(url, data=data, params=params, headers=headers) as resp:
return await resp.text()
File renamed without changes.
@@ -3,7 +3,7 @@ from tempfile import mkstemp
import settings
from db import collection
from sync.data import scan_subdirs, request
from sync.data import request
from sync.models import Model
from sync.models.DocumentPreviewImage import DocumentPreviewImage
from utils.hash import hash_str, md5
@@ -25,12 +25,6 @@ class Document(Model):
async def delete(query):
return store.find_one_and_delete(query)
@staticmethod
async def scan(provider):
scan_dir = settings.dir_documents
paths = scan_subdirs(provider, '.pdf', scan_dir)
return [Document.read_path(provider, path) for path in paths]
@staticmethod
def read_path(provider, path):
name = os.path.basename(path)
@@ -68,7 +62,7 @@ class Document(Model):
self.__hash_keys = ['id', 'url']
self.__id_template: str = '{category}-{file}'
self.__url_template: str = settings.document_url_template
self.__url_template: str = 'https://static.shlisselburg.org/art/uploads/{file}'
self.__url_preview_template: str = settings.document_url_preview_template
self.title = None
@@ -123,9 +117,8 @@ class Document(Model):
async def upload(self):
filepath = self.provider.get_local(self.file)
name = os.path.basename(self.url)
url = settings.document_url_upload_template.format(file=name)
await request.upload(url, filepath)
await request.s3_put(f'uploads/{name}', filepath)
def bake(self):
return {
@@ -182,14 +175,21 @@ async def get_pdf_title(provider, file):
from PyPDF2.generic import TextStringObject
from PyPDF2.generic import IndirectObject
def t(value):
value = str(value)
value = value.replace('\u0000', '')
if value == 'None':
return None
return value
pdf = PdfFileReader(provider.read(file))
info = pdf.getDocumentInfo()
if info:
if type(info.title) == TextStringObject:
return str(info.title)
return t(info.title)
if type(info.title_raw) == IndirectObject:
o = pdf.getObject(info.title_raw)
return str(o)
return t(info.title)
return None
@@ -7,7 +7,7 @@ from typing import Optional, List
import settings
from db import collection
from sync.data import request, list_images
from sync.data import request
from sync.models import Model
from utils.hash import md5, hash_str
from utils.image import image_magick_resize
@@ -18,10 +18,6 @@ logger = logging.getLogger(settings.name + '.Image')
store = collection(settings.collection_images)
def get_upload_url(url):
return os.path.join(settings.image_url_upload, os.path.basename(url))
def default_url_factory(file, size, ext):
url = settings.image_url_base + '{}-{}{}'
return url.format(md5(file), size, ext.lower())
@@ -58,13 +54,6 @@ class Image(Model):
return img
@staticmethod
async def scan(provider):
scan_path = settings.dir_images
documents = list_images(provider, scan_path)
return [Image.read_path(provider, i) for i in documents]
@staticmethod
def read_path(provider, path):
return Image(
@@ -115,11 +104,10 @@ class Image(Model):
async def upload(self):
if self.data:
async def fn(i):
url = get_upload_url(i['url'])
file = i['file']
filename = os.path.basename(file)
logger.info('Uploading to {}'.format(url))
await request.upload(url, file)
await request.s3_put(f'images/{filename}', file)
await asyncio.wait([fn(i) for i in self.data.values()])
@@ -161,10 +149,10 @@ class Image(Model):
def sync_image(record):
from db import db
q = {'hash': record['hash']}
q = {'file': record['file']}
try:
db().images.update_one(q, {'$set': record}, upsert=True)
i = db().images.find_one({'hash': record['hash']})
i = db().images.find_one({'file': record['file']})
return i
except ValueError:
pass
@@ -187,6 +175,11 @@ async def create_image(file: str, sizes: [()], url_fn, output_dir: str) -> Optio
_, ext = os.path.splitext(file)
images = []
if not settings.image_processing_enabled:
logger.warning(
f'Image processing disabled {file}. Size of image will be set to original'
)
async def fn(size):
size_name, width, height = size
@@ -194,10 +187,12 @@ async def create_image(file: str, sizes: [()], url_fn, output_dir: str) -> Optio
image_filename = os.path.basename(image_url)
local_image_path = os.path.join(output_dir, image_filename)
# if settings.image_processing_enabled:
image = await process_image(file, local_image_path, size)
if settings.image_processing_enabled:
image = await process_image(file, local_image_path, size)
else:
image = await read_image(file)
if not image:
logger.warning('Failed to process image {}'.format(file))
logger.warning(f'Failed to process image {file}')
return None
width, height = image.size
@@ -1,20 +1,16 @@
import os
import logging
from lxml import etree
import lxml.html
import kazimir
import settings
from db import collection
from sync.data import request
from sync.models import Model
from sync import create_date, images_from_html, title_from_html, create_post
from sync import create_date, title_from_html, create_post
from sync.models.Image import Image
from utils.hash import hash_str
from utils.io import read_yaml_md, parse_yaml_front_matter
from utils.front_matter import parse_yaml_front_matter
from utils.text.transform import url_encode_text
logger = logging.getLogger(settings.name + '.Page')
@@ -30,62 +26,77 @@ def find(store, item_id: str):
return None
class Page(Model):
@staticmethod
async def find(query):
class PageController:
def __init__(self, provider):
self.provider = provider
async def find(self, query):
return store.find(query)
@staticmethod
async def delete(query):
async def delete_item(self, query):
return store.find_one_and_delete(query)
@staticmethod
async def scan(provider):
async def get_items(self):
scan_path = settings.dir_pages
documents = [i for i in provider.scan(scan_path) if provider.is_dir(i)]
items = []
for path in self.provider.scan(scan_path):
if not self.provider.is_dir(path):
continue
item = await self.create_item(path)
if not item:
continue
items.append(item)
return items
documents = [Page.read(provider, i) for i in documents]
documents = [i for i in documents if i]
return documents
@staticmethod
def read(provider, path):
async def create_item(self, path: str):
"""
:param provider:
:param path: path to page manifest file. For example: /Pages/<Some_Page>/<Some_Page>.md
:return:
"""
dir_name = os.path.basename(path)
manifest_file = lambda ext: os.path.join(path, dir_name + ext)
manifest_path = manifest_file('.md')
if not provider.exists(manifest_path):
manifest_path = os.path.join(path, f'{dir_name}.md')
if not self.provider.exists(manifest_path):
logger.warning(f'Manifest not found on path {manifest_path}')
return None
params = {
'file': os.path.basename(manifest_path),
'folder': os.path.dirname(manifest_path),
'title': os.path.basename(manifest_path),
}
manifest = get_manifest(provider, manifest_path)
params = {
**params,
**manifest,
}
if 'url' not in params:
logger.warning('URL not specified for Page {}'.format(manifest_path))
manifest = await self.get_manifest(manifest_path)
if not manifest:
logger.warning(f'Cannot define manifest. Skip {manifest_path}')
return None
return Page(
provider,
self.provider,
manifest_path,
params=params,
params=manifest,
)
async def get_manifest(self, path: str):
data = self.provider.read(path).read().decode('utf-8')
manifest = parse_yaml_front_matter(data)
if 'url' not in manifest:
logger.warning(f'URL not specified for Page {path}')
return None
if 'date' in manifest:
manifest['date'] = create_date(
manifest['date'], settings.date_formats)
if 'until' in manifest:
manifest['until'] = create_date(
manifest['until'], settings.date_formats)
if 'id' in manifest:
manifest['id'] = str(manifest['id'])
return {
**manifest,
'file': os.path.basename(path),
'folder': os.path.dirname(path),
}
class Page(Model):
def __init__(self, provider, file, params=None):
self.__hash_salt = settings.hash_salt_pages
self.__hash_keys = ['id', 'url']
@@ -94,6 +105,7 @@ class Page(Model):
self.title = None
self.data = None
self.preview = None
self.tokens = None
self.__id_template: str = '{category}-{file}'
self.__url_template: str = settings.document_url_template
@@ -124,11 +136,12 @@ class Page(Model):
sizes = kwargs['sizes']
markdown_post = self.get_param('content')
post, images, documents = await create_post(self.provider, self.get_param('folder'), markdown_post, sizes)
post, images, documents, tokens = await create_post(self.provider, self.get_param('folder'), markdown_post, sizes)
self.title = title_from_html(post)
self.data = post
self.images = images
self.documents = documents
self.tokens = tokens
if self.has_param('preview'):
preview = self.get_param('preview')
@@ -149,6 +162,7 @@ class Page(Model):
'images': images,
'documents': documents,
'title': self.title,
'tokens': self.tokens,
'preview': self.preview.ref if self.preview else None,
}
@@ -168,9 +182,6 @@ class Page(Model):
files = []
files += self.get_param('images')
files += self.get_param('documents')
if self.has_param('contentFile'):
files += [self.get_param('contentFile')]
folder = self.get_param('folder')
files = [os.path.join(folder, x) for x in files]
files = sorted([self.file] + files)
@@ -180,23 +191,3 @@ class Page(Model):
def __str__(self):
return '<Page file={} id={}>'.format(self.file, self.id)
def get_manifest(provider, path):
data = provider.read(path).read().decode('utf-8')
manifest = parse_yaml_front_matter(data)
if 'date' in manifest:
manifest['date'] = create_date(manifest['date'], settings.date_formats)
if 'until' in manifest:
manifest['until'] = create_date(manifest['until'], settings.date_formats)
if 'id' in manifest:
manifest['id'] = str(manifest['id'])
if 'contentFile' in manifest:
dirname = os.path.dirname(path)
manifest['contentHtml'] = provider.read(os.path.join(dirname, manifest['contentFile'])).read().decode('utf-8')
return manifest
File renamed without changes.
File renamed without changes.
@@ -1,16 +1,9 @@
import re
import yaml
from kazimir import markdown_to_html
FM_BOUNDARY = re.compile(r'^-{3,}', re.MULTILINE)
def read_yaml_md(data):
yaml_front_matter, content = split_yaml_front_matter(data)
return yaml_front_matter, markdown_to_html(content)
def parse_yaml_front_matter(data: str):
fm, content = split_yaml_front_matter(data)
fm = fm if fm else {}
@@ -20,7 +13,7 @@ def parse_yaml_front_matter(data: str):
}
def split_yaml_front_matter(text, **defaults):
def split_yaml_front_matter(text: str):
"""
Parse text with YAML frontmatter, return metadata and content.
Pass in optional metadata defaults as keyword args.
@@ -29,19 +22,15 @@ def split_yaml_front_matter(text, **defaults):
and original text content.
"""
# metadata starts with defaults
metadata = defaults.copy()
# split on the first two triple-dashes
try:
_, fm, content = FM_BOUNDARY.split(text, 2)
except ValueError:
# if we can't split, bail
return metadata, text
return None, None
# parse yaml, now that we have frontmatter
fm = yaml.safe_load(fm)
if isinstance(fm, dict):
metadata.update(fm)
return metadata, content.strip()
return fm, content.strip()
return None, None
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -16,6 +16,30 @@ class YDClient:
Authorization='OAuth %s' % self.access_token,
)
async def get_flat(self, limit=20):
"""
https://cloud-api.yandex.net/v1/disk/resources/files?
[ limit=<количество файлов в списке>]
[& media_type=<тип запрашиваемых файлов>]
[& offset=<смещение относительно начала списка>]
[& fields=<нужные ключи ответа>]
[& preview_size=<размер превью>]
[& preview_crop=<признак обрезки превью>]
:return:
"""
url = '{0}/resources/files'.format(self.base_url)
payload = dict(
limit=limit,
offset=0,
)
r = requests.get(url, headers=self.base_headers, params=payload)
self.check_code(r)
json_dict = r.json()
# return Directory(**json_dict)
return json_dict
def get_disk_metadata(self):
"""
:return: disk metadata
@@ -31,6 +55,26 @@ class YDClient:
system_folders=disk['system_folders']
)
def last_uploaded(self):
"""
https://cloud-api.yandex.net/v1/disk/resources/last-uploaded?
[ limit=<количество файлов в списке>]
[& media_type=<тип запрашиваемых файлов>]
[& fields=<нужные ключи ответа>]
[& preview_size=<размер превью>]
[& preview_crop=<признак обрезки превью>]
"""
url = '{0}/resources/last-uploaded'.format(self.base_url)
payload = dict(
limit=100,
)
r = requests.get(url, headers=self.base_headers, params=payload)
self.check_code(r)
json_dict = r.json()
# return Directory(**json_dict)
return json_dict
def get_content(self, path):
"""
:param path: path to folder
+2
View File
@@ -0,0 +1,2 @@
/// <reference types="next" />
/// <reference types="next/types/global" />
+14
View File
@@ -0,0 +1,14 @@
const withCss = require('@zeit/next-css')
const withSass = require('@zeit/next-sass')
module.exports = withCss(withSass({
exportTrailingSlash: true,
env: {
APP_ARTICLES_PAGE_SIZE: 24,
APP_CARD_DEFAULT_IMAGE: 'https://art.shlisselburg.org/static/img/main.jpg',
},
webpack(config) {
config.resolve.modules.push(__dirname)
return config;
},
}))
-48
View File
@@ -1,48 +0,0 @@
server {
listen 443 ssl;
charset utf-8;
server_name art.shlisselburg.org;
ssl_certificate /etc/letsencrypt/live/art.shlisselburg.org/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/art.shlisselburg.org/privkey.pem;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers AES256+EECDH:AES256+EDH:!aNULL;
location / {
proxy_pass http://hudozka;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
}
error_log /var/log/nginx/art.shburg.error.log;
access_log /var/log/nginx/art.shburg.access.log;
}
server {
listen 80;
server_name art.shlisselburg.org art.shburg.org;
location ^~ /.well-known/acme-challenge {
root /home/hoster/www/art.shburg.org/public;
}
location / {
return 301 https://art.shlisselburg.org$request_uri;
}
}
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
upstream hudozka {
server localhost:1800;
}
+7983 -13293
View File
File diff suppressed because it is too large. Load diff
+48 -97
View File
@@ -1,99 +1,50 @@
{
"name": "Hudozka",
"private": true,
"version": "4.0.0",
"description": "",
"main": "src/bin/www.js",
"scripts": {
"start": "node src/index.js",
"build-app": "webpack --env.NODE_ENV=production --env.TARGET=app",
"out": "babel src/ -d out/",
"gulp": "gulp",
"test": "mocha --compilers js:babel-register",
"coverage": "istanbul cover mocha -- --compilers js:babel-register"
},
"repository": {
"type": "git",
"url": "https://github.com/tmshv/hudozka"
},
"author": "Roman Timashev",
"license": "ISC",
"dependencies": {
"async-file": "^2.0.2",
"classnames": "^2.2.5",
"co": "^4.4.0",
"ejson": "^2.1.2",
"handlebars": "^4.0.5",
"instagram-node": "^0.5.1",
"koa": "^2.0.0-alpha.3",
"koa-bodyparser": "^3.0.0",
"koa-compose": "^3.1.0",
"koa-conditional-get": "^1.0.2",
"koa-convert": "^1.2.0",
"koa-cookie": "^1.0.0",
"koa-etag": "^2.0.0",
"koa-helmet": "^1.0.0",
"koa-logger": "^2.0.0",
"koa-mount": "^2.0.0",
"koa-route": "^3.1.0",
"koa-session": "^4.0.0",
"koa-static": "^3.0.0",
"markdown": "^0.5.0",
"moment": "^2.18.1",
"mongodb": "^2.1.14",
"mz": "^2.4.0",
"react": "^16.3.2",
"react-dom": "^16.3.2",
"react-redux": "^4.4.8",
"react-router": "^4.2.0",
"react-router-redux": "^4.0.8",
"redux": "^3.7.2",
"redux-thunk": "^2.2.0",
"request-promise": "^2.0.1",
"sitemap": "^1.5.0",
"thunkify": "^2.1.2"
},
"devDependencies": {
"@babel/cli": "^7.0.0-beta.47",
"@babel/core": "^7.0.0-beta.47",
"@babel/plugin-proposal-class-properties": "^7.0.0-beta.47",
"@babel/polyfill": "^7.0.0-beta.47",
"@babel/preset-env": "^7.0.0-beta.47",
"@babel/register": "^7.0.0-beta.47",
"autoprefixer": "^6.3.6",
"babel-loader": "^8.0.0-beta.3",
"babel-plugin-transform-class-properties": "^6.24.1",
"babel-plugin-transform-object-rest-spread": "^6.26.0",
"babel-plugin-transform-react-jsx": "^6.23.0",
"babel-plugin-transform-regenerator": "^6.26.0",
"babel-preset-env": "^1.6.1",
"babel-register": "^6.26.0",
"css-loader": "^0.28.9",
"cssnano": "^3.4.0",
"eslint": "^3.9.1",
"eslint-config-standard": "^6.2.1",
"eslint-plugin-promise": "^3.3.1",
"eslint-plugin-react": "^7.4.0",
"eslint-plugin-standard": "^2.0.1",
"gulp": "^4.0.0",
"gulp-concat": "^2.4.1",
"gulp-if": "^2.0.0",
"gulp-imagemin": "~2.4.0",
"gulp-postcss": "^6.0.1",
"gulp-rename": "^1.2.2",
"gulp-sass": "^4.0.1",
"gulp-uglify": "~1.5.0",
"html-minify-loader": "~1.1.0",
"html-webpack-plugin": "^2.30.1",
"istanbul": "~0.4.2",
"less": "^3.0.4",
"less-loader": "^4.1.0",
"mocha": "~2.4.5",
"raw-loader": "~0.5.1",
"should": "^8.2.2",
"style-loader": "^0.20.2",
"vinyl-named": "~1.1.0",
"webpack": "^3.11.0",
"webpack-merge": "^4.1.1"
}
"name": "hudozka",
"private": true,
"version": "6.10.0",
"description": "",
"scripts": {
"start": "next dev",
"build": "npm run next-build && npm run export && npm run sitemap && npm run feed",
"next-build": "next build",
"export": "next export -o dist",
"sitemap": "node scripts/sitemap.js",
"feed": "node scripts/feed.js",
"test": "mocha --compilers js:babel-register"
},
"repository": {
"type": "git",
"url": "https://github.com/tmshv/hudozka"
},
"author": "Roman Timashev",
"license": "ISC",
"dependencies": {
"axios": "^0.19.0",
"classnames": "^2.2.6",
"date-fns": "^2.10.0",
"lodash": "^4.17.15",
"next": "^9.2.2",
"react": "^16.12.0",
"react-dom": "^16.12.0",
"sitemap": "^1.5.0",
"use-media": "^1.4.0"
},
"devDependencies": {
"@types/classnames": "^2.2.9",
"@types/lodash": "^4.14.149",
"@types/node": "^12.12.12",
"@types/react": "^16.9.12",
"@zeit/next-css": "^1.0.1",
"@zeit/next-sass": "^1.0.1",
"eslint": "^4.18.2",
"eslint-config-standard": "^6.2.1",
"eslint-plugin-promise": "^3.8.0",
"eslint-plugin-react": "^7.16.0",
"eslint-plugin-standard": "^2.0.1",
"feed": "^4.0.0",
"mocha": "^6.2.2",
"node-sass": "^4.13.0",
"should": "^8.2.2",
"typescript": "^3.7.5"
}
}
+102
View File
@@ -0,0 +1,102 @@
import Head from 'next/head'
import { App } from 'src/components/App'
import { tail } from 'lodash'
import { Page } from 'src/components/Page'
import { Meta } from 'src/components/Meta'
import { MetaBuilder } from 'src/lib/meta'
import { createApiUrl, requestGet, IResponseItems } from 'src/next-lib'
import { NextPage } from 'next'
import { IBreadcumbsPart, IMeta, IPage, ITag } from 'src/types'
function array<T>(value: T | T[]) {
return Array.isArray(value)
? value
: [value]
}
type Props = {
title: string
tags: ITag[]
date: string
content: string
breadcrumb: IBreadcumbsPart[]
meta?: IMeta
}
const Index: NextPage<Props> = props => (
<App
contentStyle={{
marginTop: 'var(--size-l)',
marginBottom: 'var(--size-xl)',
}}
breadcrumbs={props.breadcrumb}
>
<Head>
<title>{props.title}</title>
{!props.meta ? null : (
<Meta meta={props.meta} />
)}
</Head>
<Page
tags={props.tags}
date={props.date ? new Date(props.date) : null}
>
{props.content}
</Page>
</App>
)
export const unstable_getStaticProps = async (ctx: any) => {
let slug = null
if (ctx.query) {
slug = '/' + array(ctx.query.slug).join('/')
} else {
slug = '/' + array(ctx.params.slug).join('/')
}
const page = await requestGet<IPage>(createApiUrl(`/api/page?page=${slug}`), null)
if (!page) {
throw new Error(`Not found: ${slug}`)
}
const description = page.description ?? undefined
const breadcrumbSize = page?.breadcrumb?.length ?? 0
const breadcrumb = breadcrumbSize < 2 ? null : page.breadcrumb
const meta = (new MetaBuilder())
.setImage(page.preview)
.setTitle(page.title)
.setDescription(description)
.build()
return {
props: {
content: page.data,
title: page.title,
tags: page.tags,
date: page.date,
meta,
breadcrumb,
}
}
}
export const unstable_getStaticPaths = async () => {
const urls = await requestGet<IResponseItems<string>>(createApiUrl(`/api/pages/urls`), null)
if (!urls) {
return null
}
return {
paths: urls.items
.map(path => {
const slug = tail(path.split('/'))
return {
params: {
slug,
},
}
}),
}
}
export default Index
+63
View File
@@ -0,0 +1,63 @@
import 'src/style.css'
import 'src/style/content.css'
import 'src/style/article.css'
import 'src/style/marker/marker-table.css'
import 'src/style/kazimir/image.css'
import 'src/style/kazimir/video.css'
import 'src/style/style.scss'
import App from 'next/app'
import Head from 'next/head'
import { YMetrika } from 'src/components/YMetrika'
import { GAnalytics } from 'src/components/GAnalytics'
export default class MyApp extends App {
render() {
const { Component, pageProps } = this.props
return (
<>
<Head>
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width, maximum-scale=1.0" />
<meta name="referrer" content="unsafe-url" />
<meta name="google-site-verification" content="8BxOTw-Q02DS2KAdcGcnIMwiPZ58DVB18XpOfRibCcg" />
<meta name="google-site-verification" content="A-TEemUw4hHpULUDCd6xhxfHnyRbgKtss90JGKXnSpw" />
<meta name='yandex-verification' content='643c7dac144b9dac' />
<meta name="msvalidate.01" content="E878301FE3E3F12D233A6B1156889601" />
<link rel="icon" type="image/png" href="/static/graphics/favicon-32.png" />
<link rel="apple-touch-icon" sizes="57x57" href="/static/graphics/favicon-57.png" />
<link rel="apple-touch-icon" sizes="72x72" href="/static/graphics/favicon-72.png" />
<link rel="apple-touch-icon" sizes="114x114" href="/static/graphics/favicon-114.png" />
<link rel="apple-touch-icon" sizes="144x144" href="/static/graphics/favicon-144.png" />
<link
rel="alternate"
type="application/rss+xml"
title="Шлиссельбургская Детская Художественная Школа"
href="/feed.xml"
/>
<link href='/static/shadow-font/style.css' rel='stylesheet' />
{/* Opa */}
<script src="/static/opa.js" />
<link rel="stylesheet" href="/static/opa.css" />
{/* Likely */}
<script src='/static/likely.js' />
<link href='/static/likely.css' rel='stylesheet' />
{/* Instagram Embed */}
<script async defer src="//platform.instagram.com/en_US/embeds.js" />
<YMetrika account={24027460} />
<GAnalytics account={'UA-60209057-1'} />
</Head>
<Component {...pageProps} />
</>
)
}
}
+23
View File
@@ -0,0 +1,23 @@
import { NextPage } from 'next'
import { Wrapper } from 'src/components/Wrapper'
import { NotFound } from 'src/components/NotFound'
import { Copyright } from 'src/components/Copyright'
import { Block } from 'src/components/Block'
import { Spacer } from 'src/components/Spacer'
const Page: NextPage = () => (
<Wrapper
header={null}
footer={(
<Block as={'footer'} direction={'horizontal'}>
<Spacer />
<Copyright />
<Spacer />
</Block>
)}
>
<NotFound />
</Wrapper>
)
export default Page
+136
View File
@@ -0,0 +1,136 @@
import Head from 'next/head'
import { App } from 'src/components/App'
import { Meta } from 'src/components/Meta'
import { meta } from 'src/lib/meta'
import { IMeta, IPage, ImageSize } from 'src/types'
import { createApiUrl, requestGet } from 'src/next-lib'
import { NextPage, NextPageContext } from 'next'
import { CardGrid } from 'src/components/CardGrid'
import { Card } from 'src/components/Card'
import { Block } from 'src/components/Block'
import { Image } from 'src/components/Image'
import { imageSrcSet } from 'src/lib/image'
const persons = [
'/teacher/mg-timasheva',
'/teacher/va-sarzhin',
'/teacher/od-gogoleva',
'/teacher/nv-andreeva',
'/teacher/vv-voronova',
'/teacher/ea-burovtseva',
'/teacher/sa-latipova',
'/teacher/iv-khramov',
'/teacher/ma-khramova',
// АС Тимашева
// ЕЮ Тарасова
// ИН Втюрина
// МЮ Валькова
// РК Тимашев
]
type CardData = {
title: string
caption?: string
imageSrc: string
imageAlt: string
imageSrcSet: string
href: string
}
type Props = {
title: string
meta: IMeta
data: CardData[]
}
const Page: NextPage<Props> = props => {
if (!props.data) {
console.log('kek error')
return
}
const src = 'https://art.shlisselburg.org/static/img/collective.jpg'
const srcSet = imageSrcSet(src, [ImageSize.big, ImageSize.large, ImageSize.medium, ImageSize.small])
return (
<App
showAuthor={true}
wide={true}
>
<Head>
<title>{props.title}</title>
<Meta meta={props.meta} />
</Head>
<Image
src={src}
srcSet={srcSet}
style={{
marginBottom: 'var(--size-l)',
borderRadius: 'var(--radius)',
}}
/>
<CardGrid style={{
marginBottom: 'var(--size-xl)',
}}>
{props.data.map(item => (
<Card
key={item.href}
layout={'featured'}
img={{
src: item.imageSrc,
alt: item.imageAlt,
srcSet: item.imageSrcSet,
}}
href={item.href}
>
<Block direction={'vertical'}>
<span>{item.title}</span>
<span style={{
paddingTop: 'var(--size-s)',
fontSize: 'var(--font-size-second)',
}}>
{item.caption}
</span>
</Block>
</Card>
))}
</CardGrid>
</App>
)
}
export const unstable_getStaticProps = async (ctx: NextPageContext) => {
const title = 'Преподаватели Шлиссельбургской ДХШ'
const pages = await Promise.all(persons
.map(page => requestGet<IPage>(createApiUrl(`/api/page?page=${page}`), null))
)
const data: CardData[] = pages
.filter(Boolean)
.map(x => {
const image = x.preview.artifacts.large
return {
title: x.title,
caption: x.description,
href: x.url,
imageAlt: title,
imageSrc: image.src,
imageSrcSet: imageSrcSet(image.src, [ImageSize.medium, ImageSize.small])
}
})
return {
props: {
data,
title,
meta: meta({
title,
description: 'Преподаватели Шлиссельбургской ДХШ',
})
}
}
}
export default Page
+71
View File
@@ -0,0 +1,71 @@
import React from 'react'
import Head from 'next/head'
import { App } from 'src/components/App'
import Document from 'src/components/Document'
import { Share } from 'src/components/Share'
import { meta } from 'src/lib/meta'
import { Meta } from 'src/components/Meta'
import { createApiUrl, requestGet, IResponseItems } from 'src/next-lib'
import { NextPage } from 'next'
import { IMeta } from 'src/types'
type Props = {
data: any //(file)
meta: IMeta
}
const Page: NextPage<Props> = props => {
if (!props.data) {
console.log('kek error', props)
return null
}
return (
<App
showAuthor={true}
>
<Head>
<title>{props.data.title}</title>
<Meta meta={props.meta} />
</Head>
<Document {...props.data} />
<Share />
</App>
)
}
export const unstable_getStaticProps = async (ctx: any) => {
const id = ctx.params.slug
const data = await requestGet(createApiUrl(`/api/files/${id}`), {})
return {
props: {
data,
meta: meta({
// title: file.meta,
})
}
}
}
export const unstable_getStaticPaths = async () => {
const urls = await requestGet<IResponseItems<string>>(createApiUrl(`/api/files/urls`), null)
if (!urls) {
return null
}
return {
paths: urls.items
.map(x => x.replace('/document/', ''))
.map(slug => {
return {
params: {
slug,
},
}
}),
}
}
export default Page
+62
View File
@@ -0,0 +1,62 @@
import Head from 'next/head'
import { App } from 'src/components/App'
import { Meta } from 'src/components/Meta'
import { PageGrid } from 'src/components/PageGrid'
import { HudozkaTitle } from 'src/components/HudozkaTitle'
import { MetaBuilder } from 'src/lib/meta'
import { getPagesCardsByTags } from 'src/rest'
import { NextPage } from 'next'
import { IMeta, PageCardData } from 'src/types'
interface IProps {
title: string
meta: IMeta
items: PageCardData[]
}
const Index: NextPage<IProps> = props => (
<App
showAuthor={true}
wide={true}
>
<Head>
<title>{props.title}</title>
<Meta meta={props.meta} />
</Head>
<HudozkaTitle
style={{
marginBottom: 'var(--size-l)'
}}
/>
<PageGrid
items={props.items}
/>
</App>
)
export const unstable_getStaticProps = async () => {
const items = await getPagesCardsByTags([
'event',
'album',
'post',
])
const title = 'Шлиссельбургская ДХШ'
const meta = (new MetaBuilder())
.setTitle(title)
.setData({
url: '/',
})
.build()
return {
props: {
items,
title,
meta,
}
}
}
export default Index
Loaded 100 of 384 files, more files were not shown because too many files have changed in this diff. Show more