├── .formatter.exs ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── README_FA.md ├── SECURITY.md ├── apps ├── mishka_api │ ├── .formatter.exs │ ├── .gitignore │ ├── README.md │ ├── lib │ │ ├── mishka_api.ex │ │ ├── mishka_api │ │ │ ├── application.ex │ │ │ ├── plug │ │ │ │ ├── access_token_plug.ex │ │ │ │ ├── acl_check_plug.ex │ │ │ │ └── user_limiter_plug.ex │ │ │ └── protocols │ │ │ │ ├── auth_protocol.ex │ │ │ │ └── content_protocol.ex │ │ ├── mishka_api_web.ex │ │ └── mishka_api_web │ │ │ ├── channels │ │ │ └── user_socket.ex │ │ │ ├── controllers │ │ │ ├── auth_controller.ex │ │ │ └── content_controller.ex │ │ │ ├── endpoint.ex │ │ │ ├── gettext.ex │ │ │ ├── router.ex │ │ │ ├── telemetry.ex │ │ │ └── views │ │ │ ├── error_helpers.ex │ │ │ └── error_view.ex │ ├── mix.exs │ └── test │ │ ├── mishka_api_web │ │ ├── controllers │ │ │ ├── auth_controller_test.exs │ │ │ └── content_contoller_test.exs │ │ └── views │ │ │ └── error_view_test.exs │ │ ├── support │ │ ├── channel_case.ex │ │ └── conn_case.ex │ │ └── test_helper.exs ├── mishka_content │ ├── .formatter.exs │ ├── .gitignore │ ├── README.md │ ├── lib │ │ ├── blog │ │ │ ├── author.ex │ │ │ ├── category.ex │ │ │ ├── like.ex │ │ │ ├── link.ex │ │ │ ├── post.ex │ │ │ ├── tag.ex │ │ │ └── tag_mapper.ex │ │ ├── cache │ │ │ ├── bookmark_dynamic_supervisor.ex │ │ │ ├── bookmark_management.ex │ │ │ ├── content_draft_dynamic_supervisor.ex │ │ │ └── content_draft_management.ex │ │ ├── core_plugins │ │ │ ├── register │ │ │ │ └── success_register.ex │ │ │ └── user │ │ │ │ ├── login │ │ │ │ ├── success_login.ex │ │ │ │ └── success_logout.ex │ │ │ │ └── role │ │ │ │ └── success_add_role.ex │ │ ├── email │ │ │ ├── email.ex │ │ │ ├── email_helper.ex │ │ │ └── mailer.ex │ │ ├── general │ │ │ ├── activity.ex │ │ │ ├── bookmark.ex │ │ │ ├── comment.ex │ │ │ ├── comment_like.ex │ │ │ ├── notif.ex │ │ │ ├── subscription.ex │ │ │ └── user_notif_status.ex │ │ ├── mishka_content.ex │ │ ├── mishka_content │ │ │ └── application.ex │ │ └── social │ │ │ ├── facebook.ex │ │ │ ├── sender.ex │ │ │ └── twitter.ex │ ├── mix.exs │ └── test │ │ ├── activity_test.exs │ │ ├── blog │ │ ├── blog_author_test.exs │ │ ├── blog_link_test.exs │ │ ├── blog_tag_test.exs │ │ ├── category_test.exs │ │ ├── post_like_test.exs │ │ └── post_test.exs │ │ ├── bookmark_test.exs │ │ ├── comment_like_test.exs │ │ ├── comment_test.exs │ │ ├── mishka_content_test.exs │ │ ├── notif_test.exs │ │ ├── subscription_test.exs │ │ └── test_helper.exs ├── mishka_database │ ├── .formatter.exs │ ├── .gitignore │ ├── README.md │ ├── lib │ │ ├── mishka_database.ex │ │ ├── mishka_database │ │ │ ├── application.ex │ │ │ └── repo.ex │ │ └── schema │ │ │ ├── mishka_content │ │ │ ├── activity.ex │ │ │ ├── blog_author.ex │ │ │ ├── blog_like.ex │ │ │ ├── blog_link.ex │ │ │ ├── blog_tag.ex │ │ │ ├── blog_tag_mapper.ex │ │ │ ├── bookmark.ex │ │ │ ├── category.ex │ │ │ ├── comment.ex │ │ │ ├── comment_like.ex │ │ │ ├── content_schema_enum.ex │ │ │ ├── notif.ex │ │ │ ├── post.ex │ │ │ ├── post_like.ex │ │ │ ├── subscription.ex │ │ │ └── user_notif_status.ex │ │ │ └── mishka_user │ │ │ ├── identity_provider.ex │ │ │ ├── permission.ex │ │ │ ├── role.ex │ │ │ ├── user.ex │ │ │ ├── user_role.ex │ │ │ ├── user_schema_enum.ex │ │ │ └── user_token.ex │ ├── mix.exs │ ├── priv │ │ └── repo │ │ │ ├── migrations │ │ │ ├── 20210111193110_users.exs │ │ │ ├── 20210328064612_identities.exs │ │ │ ├── 20210328103652_roles.exs │ │ │ ├── 20210328103704_permissions.exs │ │ │ ├── 20210329064603_blog_categories.exs │ │ │ ├── 20210329064625_blog_posts.exs │ │ │ ├── 20210330072832_blog_tags.exs │ │ │ ├── 20210330072837_blog_tags_mappers.exs │ │ │ ├── 20210330132342_blog_authors.exs │ │ │ ├── 20210330132407_blog_likes.exs │ │ │ ├── 20210330141536_blog_links.exs │ │ │ ├── 20210330142326_subscriptions.exs │ │ │ ├── 20210330142350_bookmarks.exs │ │ │ ├── 20210330142430_notifs.exs │ │ │ ├── 20210330162305_comments.exs │ │ │ ├── 20210330224243_comments_likes.exs │ │ │ ├── 20210402080613_users_roles.exs │ │ │ ├── 20211005180905_user_notif_statuses.exs │ │ │ └── 20220626144233_user_tokens.exs │ │ │ └── seeds.exs │ └── test │ │ ├── helpers │ │ └── mishka_database_crud_macro_test.exs │ │ └── test_helper.exs ├── mishka_file │ ├── .formatter.exs │ ├── .gitignore │ ├── README.md │ ├── lib │ │ ├── mishka_file.ex │ │ └── mishka_file │ │ │ └── application.ex │ ├── mix.exs │ └── test │ │ ├── mishka_file_test.exs │ │ └── test_helper.exs ├── mishka_html │ ├── .formatter.exs │ ├── .gitignore │ ├── README.md │ ├── assets │ │ ├── css │ │ │ ├── app.css │ │ │ └── phoenix.css │ │ ├── js │ │ │ └── app.js │ │ ├── static │ │ │ ├── css │ │ │ │ ├── bootstrap.min.css │ │ │ │ ├── bootstrap.min.css.map │ │ │ │ ├── ckeditor-styles.css │ │ │ │ ├── default-template.css │ │ │ │ ├── font.css │ │ │ │ └── main.min.css │ │ │ ├── favicon.ico │ │ │ ├── fonts │ │ │ │ ├── Iconly-bulk.eot │ │ │ │ ├── Iconly-bulk.svg │ │ │ │ ├── Iconly-bulk.ttf │ │ │ │ ├── Iconly-bulk.woff │ │ │ │ ├── Iconly-light.eot │ │ │ │ ├── Vazir-Regular.eot │ │ │ │ ├── Vazir-Regular.ttf │ │ │ │ ├── Vazir-Regular.woff │ │ │ │ └── Vazir-Regular.woff2 │ │ │ ├── images │ │ │ │ ├── 1.jpg │ │ │ │ ├── 2.jpg │ │ │ │ ├── 3.jpg │ │ │ │ ├── 4.jpg │ │ │ │ ├── 5.jpg │ │ │ │ ├── icons8-login-as-user-80.png │ │ │ │ ├── mylogo.png │ │ │ │ └── no-user-image.jpg │ │ │ ├── js │ │ │ │ ├── bootstrap.bundle.min.js │ │ │ │ ├── bootstrap.bundle.min.js.map │ │ │ │ ├── bootstrap.min.js │ │ │ │ ├── bootstrap.min.js.map │ │ │ │ ├── check_editor_extended.js │ │ │ │ ├── ckeditor.js │ │ │ │ ├── ckeditor.js.map │ │ │ │ ├── main.min.js │ │ │ │ └── translations │ │ │ │ │ ├── af.js │ │ │ │ │ ├── ar.js │ │ │ │ │ ├── ast.js │ │ │ │ │ ├── az.js │ │ │ │ │ ├── bg.js │ │ │ │ │ ├── ca.js │ │ │ │ │ ├── cs.js │ │ │ │ │ ├── da.js │ │ │ │ │ ├── de-ch.js │ │ │ │ │ ├── de.js │ │ │ │ │ ├── el.js │ │ │ │ │ ├── en-au.js │ │ │ │ │ ├── en-gb.js │ │ │ │ │ ├── eo.js │ │ │ │ │ ├── es.js │ │ │ │ │ ├── et.js │ │ │ │ │ ├── eu.js │ │ │ │ │ ├── fa.js │ │ │ │ │ ├── fi.js │ │ │ │ │ ├── fr.js │ │ │ │ │ ├── gl.js │ │ │ │ │ ├── gu.js │ │ │ │ │ ├── he.js │ │ │ │ │ ├── hi.js │ │ │ │ │ ├── hr.js │ │ │ │ │ ├── hu.js │ │ │ │ │ ├── id.js │ │ │ │ │ ├── it.js │ │ │ │ │ ├── ja.js │ │ │ │ │ ├── kk.js │ │ │ │ │ ├── km.js │ │ │ │ │ ├── kn.js │ │ │ │ │ ├── ko.js │ │ │ │ │ ├── ku.js │ │ │ │ │ ├── lt.js │ │ │ │ │ ├── lv.js │ │ │ │ │ ├── nb.js │ │ │ │ │ ├── ne.js │ │ │ │ │ ├── nl.js │ │ │ │ │ ├── no.js │ │ │ │ │ ├── oc.js │ │ │ │ │ ├── pl.js │ │ │ │ │ ├── pt-br.js │ │ │ │ │ ├── pt.js │ │ │ │ │ ├── ro.js │ │ │ │ │ ├── ru.js │ │ │ │ │ ├── si.js │ │ │ │ │ ├── sk.js │ │ │ │ │ ├── sl.js │ │ │ │ │ ├── sq.js │ │ │ │ │ ├── sr-latn.js │ │ │ │ │ ├── sr.js │ │ │ │ │ ├── sv.js │ │ │ │ │ ├── th.js │ │ │ │ │ ├── tk.js │ │ │ │ │ ├── tr.js │ │ │ │ │ ├── tt.js │ │ │ │ │ ├── ug.js │ │ │ │ │ ├── uk.js │ │ │ │ │ ├── vi.js │ │ │ │ │ ├── zh-cn.js │ │ │ │ │ └── zh.js │ │ │ └── robots.txt │ │ └── vendor │ │ │ └── topbar.js │ ├── lib │ │ ├── mishka_html.ex │ │ ├── mishka_html │ │ │ ├── application.ex │ │ │ ├── helpers │ │ │ │ └── live_crud.ex │ │ │ └── plug │ │ │ │ ├── acl_check_plug.ex │ │ │ │ ├── current_token_plug.ex │ │ │ │ ├── live_acl_check_plug.ex │ │ │ │ └── not_login_plug.ex │ │ ├── mishka_html_web.ex │ │ └── mishka_html_web │ │ │ ├── channels │ │ │ └── user_socket.ex │ │ │ ├── controllers │ │ │ └── auth_controller.ex │ │ │ ├── endpoint.ex │ │ │ ├── gettext.ex │ │ │ ├── live │ │ │ ├── admin_activities_live.ex │ │ │ ├── admin_activity_live.ex │ │ │ ├── admin_blog_categories_live.ex │ │ │ ├── admin_blog_category_live.ex │ │ │ ├── admin_blog_post_authors_live.ex │ │ │ ├── admin_blog_post_live.ex │ │ │ ├── admin_blog_post_tags_live.ex │ │ │ ├── admin_blog_posts_live.ex │ │ │ ├── admin_blog_tag_live.ex │ │ │ ├── admin_blog_tags_live.ex │ │ │ ├── admin_comment_live.ex │ │ │ ├── admin_comments_live.ex │ │ │ ├── admin_dashboard_live.ex │ │ │ ├── admin_link_live.ex │ │ │ ├── admin_links_live.ex │ │ │ ├── admin_media_manager_live.ex │ │ │ ├── admin_notif.ex │ │ │ ├── admin_notifs.ex │ │ │ ├── admin_seo_live.ex │ │ │ ├── admin_setting_live.ex │ │ │ ├── admin_settings_live.ex │ │ │ ├── admin_subscription_live.ex │ │ │ ├── admin_subscriptions_live.ex │ │ │ ├── admin_user_live.ex │ │ │ ├── admin_user_role_live.ex │ │ │ ├── admin_user_role_permissions_live.ex │ │ │ ├── admin_user_roles_live.ex │ │ │ ├── admin_users_live.ex │ │ │ ├── blog_category_live.ex │ │ │ ├── blog_post_live.ex │ │ │ ├── blogs_live.ex │ │ │ ├── bookmarks_live.ex │ │ │ ├── components │ │ │ │ ├── admin │ │ │ │ │ ├── dashboard │ │ │ │ │ │ ├── admin_dashboard_activities.ex │ │ │ │ │ │ ├── admin_dashboard_last_users_component.ex │ │ │ │ │ │ ├── admin_dashboard_quick_menu.ex │ │ │ │ │ │ ├── admin_last_blog_posts_component.ex │ │ │ │ │ │ └── admin_last_notif_component.ex │ │ │ │ │ ├── form │ │ │ │ │ │ ├── add_field_component.ex │ │ │ │ │ │ ├── add_tag_component.ex │ │ │ │ │ │ ├── converte_title_to_link_component.ex │ │ │ │ │ │ ├── editor_component.ex │ │ │ │ │ │ ├── select_component.ex │ │ │ │ │ │ ├── text_component.ex │ │ │ │ │ │ ├── text_search_component.ex │ │ │ │ │ │ ├── textarea_component.ex │ │ │ │ │ │ └── upload_component.ex │ │ │ │ │ ├── public │ │ │ │ │ │ ├── _admin_menu.ex │ │ │ │ │ │ ├── _live_flash_component.ex │ │ │ │ │ │ ├── _modal_component.ex │ │ │ │ │ │ ├── _notif.ex │ │ │ │ │ │ ├── admin_calendar_component.ex │ │ │ │ │ │ └── draft_block_component.ex │ │ │ │ │ └── setting │ │ │ │ │ │ └── add_field_component.ex │ │ │ │ ├── client │ │ │ │ │ ├── blog_post │ │ │ │ │ │ └── sub_comment.ex │ │ │ │ │ ├── home │ │ │ │ │ │ ├── banner_block_component.ex │ │ │ │ │ │ └── normal_block_component.ex │ │ │ │ │ ├── login │ │ │ │ │ │ └── login_form_component.ex │ │ │ │ │ ├── public │ │ │ │ │ │ ├── _client_header_component.ex │ │ │ │ │ │ ├── _client_menu_and_notif.ex │ │ │ │ │ │ └── _cright_component.ex │ │ │ │ │ └── register │ │ │ │ │ │ └── register_form_component.ex │ │ │ │ └── public │ │ │ │ │ ├── _pagination_component.ex │ │ │ │ │ ├── _time_converter_component.ex │ │ │ │ │ ├── activities_component.ex │ │ │ │ │ ├── flash_component.ex │ │ │ │ │ ├── list_container_component.ex │ │ │ │ │ ├── list_item_component.ex │ │ │ │ │ ├── notif.ex │ │ │ │ │ ├── search_component.ex │ │ │ │ │ └── time_converter_component.ex │ │ │ ├── home_live.ex │ │ │ ├── login_live.ex │ │ │ ├── notif_live.ex │ │ │ ├── notifs_live.ex │ │ │ ├── register_live.ex │ │ │ ├── reset_change_password_live.ex │ │ │ └── reset_password_live.ex │ │ │ ├── router.ex │ │ │ ├── telemetry.ex │ │ │ ├── templates │ │ │ ├── admin_activity │ │ │ │ ├── admin_activities_live.html.heex │ │ │ │ └── admin_activity_live.html.heex │ │ │ ├── admin_blog │ │ │ │ ├── admin_blog_category_live.html.heex │ │ │ │ ├── admin_blog_post_live.html.heex │ │ │ │ ├── admin_blog_tag_live.html.heex │ │ │ │ └── admin_link_live.html.heex │ │ │ ├── admin_comment │ │ │ │ └── admin_comment_live.html.heex │ │ │ ├── admin_dashboard │ │ │ │ └── admin_dashboard_live.html.heex │ │ │ ├── admin_media_manager │ │ │ │ └── admin_media_manager_live.html.heex │ │ │ ├── admin_notif │ │ │ │ ├── admin_notif_live.html.heex │ │ │ │ └── admin_notif_show_live.html.heex │ │ │ ├── admin_seo │ │ │ │ └── admin_seo_live.html.heex │ │ │ ├── admin_setting │ │ │ │ └── admin_setting_live.html.heex │ │ │ ├── admin_subscription │ │ │ │ └── admin_subscription_live.html.heex │ │ │ ├── admin_user │ │ │ │ ├── admin_user_live.html.heex │ │ │ │ └── admin_user_role_live.html.heex │ │ │ ├── client_auth │ │ │ │ ├── login_live.html.heex │ │ │ │ ├── register_live.html.heex │ │ │ │ ├── reset_change_password_live.html.heex │ │ │ │ └── reset_password_live.html.heex │ │ │ ├── client_blog │ │ │ │ ├── blog_category_live.html.heex │ │ │ │ ├── blog_post_live.html.heex │ │ │ │ ├── blogs_live.html.heex │ │ │ │ └── bookmarks_live.html.heex │ │ │ ├── client_home │ │ │ │ └── home_live.html.heex │ │ │ ├── client_notif │ │ │ │ ├── notif_live.html.heex │ │ │ │ └── notifs_live.html.heex │ │ │ └── layout │ │ │ │ ├── app.html.heex │ │ │ │ ├── live.html.heex │ │ │ │ └── root.html.heex │ │ │ └── views │ │ │ ├── admin_activity_view.ex │ │ │ ├── admin_blog_view.ex │ │ │ ├── admin_comment_view.ex │ │ │ ├── admin_dashboard_view.ex │ │ │ ├── admin_media_manager_view.ex │ │ │ ├── admin_notif_view.ex │ │ │ ├── admin_seo_view.ex │ │ │ ├── admin_setting_view.ex │ │ │ ├── admin_subscription_view.ex │ │ │ ├── admin_user_view.ex │ │ │ ├── client_auth_view.ex │ │ │ ├── client_blog_view.ex │ │ │ ├── client_home_view.ex │ │ │ ├── client_notif_view.ex │ │ │ ├── error_helpers.ex │ │ │ ├── error_view.ex │ │ │ └── layout_view.ex │ ├── mix.exs │ ├── priv │ │ └── static │ │ │ ├── cache_manifest.json │ │ │ ├── css │ │ │ ├── bootstrap-icons.css │ │ │ └── font.css │ │ │ ├── favicon.ico │ │ │ ├── fonts │ │ │ ├── Iconly-bulk.eot │ │ │ ├── Iconly-bulk.svg │ │ │ ├── Iconly-bulk.ttf │ │ │ ├── Iconly-bulk.woff │ │ │ ├── Iconly-light.eot │ │ │ ├── Vazir-Regular.eot │ │ │ ├── Vazir-Regular.ttf │ │ │ ├── Vazir-Regular.woff │ │ │ ├── Vazir-Regular.woff2 │ │ │ ├── bootstrap-icons.woff │ │ │ ├── bootstrap-icons.woff2 │ │ │ └── font.css │ │ │ ├── images │ │ │ ├── 1.jpg │ │ │ ├── 2.jpg │ │ │ ├── 3.jpg │ │ │ ├── 4.jpg │ │ │ ├── 5.jpg │ │ │ ├── icons8-login-as-user-80.png │ │ │ ├── mylogo.png │ │ │ └── no-user-image.jpg │ │ │ ├── js │ │ │ ├── bootstrap.bundle.min.js │ │ │ ├── bootstrap.bundle.min.js.map │ │ │ ├── bootstrap.min.js │ │ │ ├── bootstrap.min.js.map │ │ │ ├── check_editor_extended.js │ │ │ ├── ckeditor.js │ │ │ ├── ckeditor.js.map │ │ │ ├── main.min.js │ │ │ └── translations │ │ │ │ ├── af.js │ │ │ │ ├── ar.js │ │ │ │ ├── ast.js │ │ │ │ ├── az.js │ │ │ │ ├── bg.js │ │ │ │ ├── ca.js │ │ │ │ ├── cs.js │ │ │ │ ├── da.js │ │ │ │ ├── de-ch.js │ │ │ │ ├── de.js │ │ │ │ ├── el.js │ │ │ │ ├── en-au.js │ │ │ │ ├── en-gb.js │ │ │ │ ├── eo.js │ │ │ │ ├── es.js │ │ │ │ ├── et.js │ │ │ │ ├── eu.js │ │ │ │ ├── fa.js │ │ │ │ ├── fi.js │ │ │ │ ├── fr.js │ │ │ │ ├── gl.js │ │ │ │ ├── gu.js │ │ │ │ ├── he.js │ │ │ │ ├── hi.js │ │ │ │ ├── hr.js │ │ │ │ ├── hu.js │ │ │ │ ├── id.js │ │ │ │ ├── it.js │ │ │ │ ├── ja.js │ │ │ │ ├── kk.js │ │ │ │ ├── km.js │ │ │ │ ├── kn.js │ │ │ │ ├── ko.js │ │ │ │ ├── ku.js │ │ │ │ ├── lt.js │ │ │ │ ├── lv.js │ │ │ │ ├── nb.js │ │ │ │ ├── ne.js │ │ │ │ ├── nl.js │ │ │ │ ├── no.js │ │ │ │ ├── oc.js │ │ │ │ ├── pl.js │ │ │ │ ├── pt-br.js │ │ │ │ ├── pt.js │ │ │ │ ├── ro.js │ │ │ │ ├── ru.js │ │ │ │ ├── si.js │ │ │ │ ├── sk.js │ │ │ │ ├── sl.js │ │ │ │ ├── sq.js │ │ │ │ ├── sr-latn.js │ │ │ │ ├── sr.js │ │ │ │ ├── sv.js │ │ │ │ ├── th.js │ │ │ │ ├── tk.js │ │ │ │ ├── tr.js │ │ │ │ ├── tt.js │ │ │ │ ├── ug.js │ │ │ │ ├── uk.js │ │ │ │ ├── vi.js │ │ │ │ ├── zh-cn.js │ │ │ │ └── zh.js │ │ │ └── robots.txt │ └── test │ │ ├── mishka_html_web │ │ ├── live │ │ │ └── page_live_test.exs │ │ └── views │ │ │ ├── error_view_test.exs │ │ │ └── layout_view_test.exs │ │ ├── support │ │ ├── channel_case.ex │ │ └── conn_case.ex │ │ └── test_helper.exs ├── mishka_translator │ ├── .formatter.exs │ ├── .gitignore │ ├── README.md │ ├── lib │ │ ├── gettext.ex │ │ ├── mishka_translator.ex │ │ └── mishka_translator │ │ │ └── application.ex │ ├── mix.exs │ ├── priv │ │ └── gettext │ │ │ ├── api_auth.pot │ │ │ ├── api_content.pot │ │ │ ├── content_email.pot │ │ │ ├── db_schema_content.pot │ │ │ ├── db_schema_public.pot │ │ │ ├── db_schema_user.pot │ │ │ ├── default.pot │ │ │ ├── en │ │ │ └── LC_MESSAGES │ │ │ │ ├── api_auth.po │ │ │ │ ├── api_content.po │ │ │ │ ├── content_email.po │ │ │ │ ├── db_schema_content.po │ │ │ │ ├── db_schema_public.po │ │ │ │ ├── db_schema_user.po │ │ │ │ ├── default.po │ │ │ │ ├── errors.po │ │ │ │ ├── html_auth.po │ │ │ │ ├── html_live.po │ │ │ │ ├── html_live_component.po │ │ │ │ ├── html_live_templates.po │ │ │ │ ├── macro_live.po │ │ │ │ ├── user_captcha.po │ │ │ │ └── users.po │ │ │ ├── errors.pot │ │ │ ├── fa │ │ │ └── LC_MESSAGES │ │ │ │ ├── api_auth.po │ │ │ │ ├── api_content.po │ │ │ │ ├── content_email.po │ │ │ │ ├── db_schema_content.po │ │ │ │ ├── db_schema_public.po │ │ │ │ ├── db_schema_user.po │ │ │ │ ├── default.po │ │ │ │ ├── errors.po │ │ │ │ ├── html_auth.po │ │ │ │ ├── html_live.po │ │ │ │ ├── html_live_component.po │ │ │ │ ├── html_live_templates.po │ │ │ │ ├── macro_live.po │ │ │ │ ├── user_captcha.po │ │ │ │ └── users.po │ │ │ ├── html_auth.pot │ │ │ ├── html_live.pot │ │ │ ├── html_live_component.pot │ │ │ ├── html_live_templates.pot │ │ │ ├── macro_live.pot │ │ │ ├── user_captcha.pot │ │ │ └── users.pot │ └── test │ │ ├── mishka_translator_test.exs │ │ └── test_helper.exs └── mishka_user │ ├── .formatter.exs │ ├── .gitignore │ ├── README.md │ ├── lib │ ├── acl │ │ ├── access.ex │ │ ├── acl_management.ex │ │ ├── action.ex │ │ ├── permission.ex │ │ ├── role.ex │ │ └── user_role.ex │ ├── core_plugins │ │ └── login │ │ │ ├── success_login.ex │ │ │ └── success_logout.ex │ ├── guardian │ │ ├── auth_error_handler.ex │ │ ├── auth_pipeline.ex │ │ └── guardian.ex │ ├── identity.ex │ ├── mishka_user.ex │ ├── mishka_user │ │ └── application.ex │ ├── token │ │ ├── current_phoenix_token.ex │ │ ├── jwt_token.ex │ │ ├── phoenix_token.ex │ │ ├── token.ex │ │ ├── token_managemnt.ex │ │ └── user_token.ex │ ├── user.ex │ ├── validation │ │ ├── google_recaptcha.ex │ │ ├── random_code.ex │ │ └── user_input.ex │ └── worker │ │ ├── expire_random_code_worker.ex │ │ └── expire_token_worker.ex │ ├── mix.exs │ └── test │ ├── acl │ ├── permission_test.exs │ ├── role_test.exs │ └── user_role_test.exs │ ├── mishka_user_test.exs │ ├── test_helper.exs │ └── token │ └── token_test.exs ├── config ├── config.exs ├── dev.exs ├── prod.exs ├── prod.secret.exs └── test.exs ├── deployment └── docker │ ├── bin │ ├── onefetch_linux │ └── onefetch_macos │ ├── dockers │ ├── Dockerfile │ ├── docker-compose_dev_with_nginx.yml │ ├── docker-compose_dev_without_nginx.yml │ ├── docker-compose_with_nginx.yml │ ├── docker-compose_without_nginx.yml │ └── entrypoint.sh │ ├── docs │ └── mishka-logo.ans │ ├── etc │ ├── nginx │ │ └── conf │ │ │ ├── conf.d │ │ │ ├── default.conf │ │ │ ├── mishka_api.conf │ │ │ └── mishka_cms.conf │ │ │ ├── fastcgi.conf │ │ │ ├── fastcgi_params │ │ │ ├── mime.types │ │ │ ├── modules │ │ │ ├── nginx.conf │ │ │ ├── sample_conf │ │ │ ├── mishka_api.conf │ │ │ ├── mishka_cms.conf │ │ │ ├── ssl_dev.conf │ │ │ └── ssl_prod.conf │ │ │ ├── scgi_params │ │ │ ├── ssl.conf │ │ │ └── uwsgi_params │ └── ssl │ │ ├── dev │ │ ├── rootCA_example.pem │ │ ├── server_example.crt │ │ └── server_example.key │ │ └── letsencrypt │ │ ├── dhparam2048.pem │ │ └── lets-encrypt-x3-cross-signed.pem │ ├── mishka.sh │ └── src │ ├── functions.sh │ └── variables.sh ├── integration_test └── postman │ └── v1 │ └── mishkacms-api.json └── mix.exs /.formatter.exs: -------------------------------------------------------------------------------- 1 | [ 2 | inputs: ["mix.exs", "config/*.exs"], 3 | subdirectories: ["apps/*"] 4 | ] 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # The directory Mix will write compiled artifacts to. 2 | /_build/ 3 | 4 | # If you run "mix test --cover", coverage assets end up here. 5 | /cover/ 6 | 7 | # The directory Mix downloads your dependencies sources to. 8 | /deps/ 9 | 10 | # Where 3rd-party dependencies like ExDoc output generated docs. 11 | /doc/ 12 | 13 | # Ignore .fetch files in case you like to edit your project deps locally. 14 | /.fetch 15 | 16 | # If the VM crashes, it generates a dump, let's ignore it too. 17 | erl_crash.dump 18 | 19 | # Also ignore archive artifacts (built via "mix archive.build"). 20 | *.ez 21 | 22 | 23 | # General 24 | .DS_Store 25 | Desktop.ini 26 | .AppleDouble 27 | .LSOverride 28 | 29 | 30 | # Icon must end with two \r 31 | Icon 32 | Thumbs.db 33 | # Thumbnails 34 | ._* 35 | 36 | # Files that might appear in the root of a volume 37 | .DocumentRevisions-V100 38 | .fseventsd 39 | .Spotlight-V100 40 | .TemporaryItems 41 | .Trashes 42 | .VolumeIcon.icns 43 | .com.apple.timemachine.donotpresent 44 | 45 | # Directories potentially created on remote AFP share 46 | .AppleDB 47 | .AppleDesktop 48 | Network Trash Folder 49 | Temporary Items 50 | .apdisk 51 | 52 | # Compiled Python files 53 | *.pyc 54 | 55 | # Compiled C++ files 56 | *.out 57 | 58 | Dockerfile_postgres 59 | init_db.sh 60 | 61 | mix.lock 62 | 63 | 64 | # Migration 65 | apps/mishka_database/priv/repo/migrations/20220622100108_setting_migration.exs 66 | apps/mishka_database/priv/repo/migrations/20220622100110_plugin_migration.exs 67 | apps/mishka_database/priv/repo/migrations/20220622100112_oban_migration.exs 68 | apps/mishka_database/priv/repo/migrations/20220622100114_dependency_migration.exs 69 | apps/mishka_database/priv/repo/migrations/20220622100116_activity_migration.exs 70 | 71 | # Prevent test folder 72 | **/deployment/extensions 73 | .elixir_ls -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | start_shell: 2 | cd deployment/docker; chmod +x mishka.sh; sudo ./mishka.sh; 3 | 4 | start_elixir: 5 | mix deps.get 6 | mix deps.compile 7 | mix ecto.create 8 | cd apps/mishka_database; mix mishka_installer.db.gen.migration || true 9 | mix ecto.migrate 10 | mix assets.deploy || true 11 | mix run apps/mishka_database/priv/repo/seeds.exs 12 | iex -S mix phx.server 13 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | MishkaCms applies bug fixes only to the latest minor branch. Security patches are available for the last 2 minor branches: 6 | 7 | | Version | Supported | 8 | | ------- | ------------------ | 9 | | 0.0.2 | Bug fixes and security patches | 10 | | 0.0.1 | Has been stopped| 11 | 12 | ## Reporting a Vulnerability 13 | 14 | Please disclose security vulnerabilities privately at shahryar.tbiz@gmail.com 15 | -------------------------------------------------------------------------------- /apps/mishka_api/.formatter.exs: -------------------------------------------------------------------------------- 1 | [ 2 | import_deps: [:phoenix], 3 | inputs: ["*.{ex,exs}", "{config,lib,test}/**/*.{ex,exs}"] 4 | ] 5 | -------------------------------------------------------------------------------- /apps/mishka_api/.gitignore: -------------------------------------------------------------------------------- 1 | # The directory Mix will write compiled artifacts to. 2 | /_build/ 3 | 4 | # If you run "mix test --cover", coverage assets end up here. 5 | /cover/ 6 | 7 | # The directory Mix downloads your dependencies sources to. 8 | /deps/ 9 | 10 | # Where 3rd-party dependencies like ExDoc output generated docs. 11 | /doc/ 12 | 13 | # Ignore .fetch files in case you like to edit your project deps locally. 14 | /.fetch 15 | 16 | # If the VM crashes, it generates a dump, let's ignore it too. 17 | erl_crash.dump 18 | 19 | # Also ignore archive artifacts (built via "mix archive.build"). 20 | *.ez 21 | 22 | # Ignore package tarball (built via "mix hex.build"). 23 | mishka_api-*.tar 24 | 25 | # Since we are building assets from assets/, 26 | # we ignore priv/static. You may want to comment 27 | # this depending on your deployment strategy. 28 | /priv/static/ 29 | -------------------------------------------------------------------------------- /apps/mishka_api/README.md: -------------------------------------------------------------------------------- 1 | # MishkaApi 2 | 3 | To start your Phoenix server: 4 | 5 | * Install dependencies with `mix deps.get` 6 | * Start Phoenix endpoint with `mix phx.server` 7 | 8 | Now you can visit [`localhost:4000`](http://localhost:4000) from your browser. 9 | 10 | Ready to run in production? Please [check our deployment guides](https://hexdocs.pm/phoenix/deployment.html). 11 | 12 | ## Learn more 13 | 14 | * Official website: https://www.phoenixframework.org/ 15 | * Guides: https://hexdocs.pm/phoenix/overview.html 16 | * Docs: https://hexdocs.pm/phoenix 17 | * Forum: https://elixirforum.com/c/phoenix-forum 18 | * Source: https://github.com/phoenixframework/phoenix 19 | -------------------------------------------------------------------------------- /apps/mishka_api/lib/mishka_api.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaApi do 2 | @moduledoc """ 3 | MishkaApi keeps the contexts that define your domain 4 | and business logic. 5 | 6 | Contexts are also responsible for managing your data, regardless 7 | if it comes from the database, an external API or others. 8 | """ 9 | 10 | def get_config(item) do 11 | :mishka_api 12 | |> Application.fetch_env!(:auth) 13 | |> Keyword.fetch!(item) 14 | end 15 | 16 | def cowboy_ip(conn) do 17 | to_string(:inet_parse.ntoa(conn.remote_ip)) 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /apps/mishka_api/lib/mishka_api/application.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaApi.Application do 2 | # See https://hexdocs.pm/elixir/Application.html 3 | # for more information on OTP Applications 4 | @moduledoc false 5 | 6 | use Application 7 | 8 | def start(_type, _args) do 9 | children = [ 10 | # Start the Telemetry supervisor 11 | MishkaApiWeb.Telemetry, 12 | # Start the PubSub system 13 | {Phoenix.PubSub, name: MishkaApi.PubSub}, 14 | # Start the Endpoint (http/https) 15 | MishkaApiWeb.Endpoint 16 | # Start a worker by calling: MishkaApi.Worker.start_link(arg) 17 | # {MishkaApi.Worker, arg} 18 | ] 19 | 20 | # See https://hexdocs.pm/elixir/Supervisor.html 21 | # for other strategies and supported options 22 | opts = [strategy: :one_for_one, name: MishkaApi.Supervisor] 23 | Supervisor.start_link(children, opts) 24 | end 25 | 26 | # Tell Phoenix to update the endpoint configuration 27 | # whenever the application is updated. 28 | def config_change(changed, _new, removed) do 29 | MishkaApiWeb.Endpoint.config_change(changed, removed) 30 | :ok 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /apps/mishka_api/lib/mishka_api/plug/user_limiter_plug.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaApi.Plug.UserLimiterPlug do 2 | # how many requests user can send per second 3 | end 4 | -------------------------------------------------------------------------------- /apps/mishka_api/lib/mishka_api_web/channels/user_socket.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaApiWeb.UserSocket do 2 | use Phoenix.Socket 3 | 4 | ## Channels 5 | # channel "room:*", MishkaApiWeb.RoomChannel 6 | 7 | # Socket params are passed from the client and can 8 | # be used to verify and authenticate a user. After 9 | # verification, you can put default assigns into 10 | # the socket that will be set for all channels, ie 11 | # 12 | # {:ok, assign(socket, :user_id, verified_user_id)} 13 | # 14 | # To deny connection, return `:error`. 15 | # 16 | # See `Phoenix.Token` documentation for examples in 17 | # performing token verification on connect. 18 | @impl true 19 | def connect(_params, socket, _connect_info) do 20 | {:ok, socket} 21 | end 22 | 23 | # Socket id's are topics that allow you to identify all sockets for a given user: 24 | # 25 | # def id(socket), do: "user_socket:#{socket.assigns.user_id}" 26 | # 27 | # Would allow you to broadcast a "disconnect" event and terminate 28 | # all active sockets and channels for a given user: 29 | # 30 | # MishkaApiWeb.Endpoint.broadcast("user_socket:#{user.id}", "disconnect", %{}) 31 | # 32 | # Returning `nil` makes this socket anonymous. 33 | @impl true 34 | def id(_socket), do: nil 35 | end 36 | -------------------------------------------------------------------------------- /apps/mishka_api/lib/mishka_api_web/endpoint.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaApiWeb.Endpoint do 2 | use Phoenix.Endpoint, otp_app: :mishka_api 3 | 4 | # The session will be stored in the cookie and signed, 5 | # this means its contents can be read but not tampered with. 6 | # Set :encryption_salt if you would also like to encrypt it. 7 | @session_options [ 8 | store: :cookie, 9 | key: "_mishka_api_key", 10 | signing_salt: "AmmcTDEq" 11 | ] 12 | 13 | socket "/socket", MishkaApiWeb.UserSocket, 14 | websocket: true, 15 | longpoll: false 16 | 17 | socket "/live", Phoenix.LiveView.Socket, websocket: [connect_info: [session: @session_options]] 18 | 19 | # Serve at "/" the static files from "priv/static" directory. 20 | # 21 | # You should set gzip to true if you are running phx.digest 22 | # when deploying your static files in production. 23 | plug Plug.Static, 24 | at: "/", 25 | from: :mishka_api, 26 | gzip: false, 27 | only: ~w(css fonts images js favicon.ico robots.txt) 28 | 29 | # Code reloading can be explicitly enabled under the 30 | # :code_reloader configuration of your endpoint. 31 | if code_reloading? do 32 | plug Phoenix.CodeReloader 33 | end 34 | 35 | plug Phoenix.LiveDashboard.RequestLogger, 36 | param_key: "request_logger", 37 | cookie_key: "request_logger" 38 | 39 | plug Plug.RequestId 40 | plug Plug.Telemetry, event_prefix: [:phoenix, :endpoint] 41 | 42 | plug Plug.Parsers, 43 | parsers: [:urlencoded, :multipart, :json], 44 | pass: ["*/*"], 45 | json_decoder: Phoenix.json_library() 46 | 47 | plug Plug.MethodOverride 48 | plug Plug.Head 49 | plug Plug.Session, @session_options 50 | plug MishkaApiWeb.Router 51 | end 52 | -------------------------------------------------------------------------------- /apps/mishka_api/lib/mishka_api_web/gettext.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaApiWeb.Gettext do 2 | @moduledoc """ 3 | A module providing Internationalization with a gettext-based API. 4 | 5 | By using [Gettext](https://hexdocs.pm/gettext), 6 | your module gains a set of macros for translations, for example: 7 | 8 | import MishkaApiWeb.Gettext 9 | 10 | # Simple translation 11 | gettext("Here is the string to translate") 12 | 13 | # Plural translation 14 | ngettext("Here is the string to translate", 15 | "Here are the strings to translate", 16 | 3) 17 | 18 | # Domain-based translation 19 | dgettext("errors", "Here is the error message to translate") 20 | 21 | See the [Gettext Docs](https://hexdocs.pm/gettext) for detailed usage. 22 | """ 23 | use Gettext, otp_app: :mishka_api 24 | end 25 | -------------------------------------------------------------------------------- /apps/mishka_api/lib/mishka_api_web/telemetry.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaApiWeb.Telemetry do 2 | use Supervisor 3 | import Telemetry.Metrics 4 | 5 | def start_link(arg) do 6 | Supervisor.start_link(__MODULE__, arg, name: __MODULE__) 7 | end 8 | 9 | @impl true 10 | def init(_arg) do 11 | children = [ 12 | # Telemetry poller will execute the given period measurements 13 | # every 10_000ms. Learn more here: https://hexdocs.pm/telemetry_metrics 14 | {:telemetry_poller, measurements: periodic_measurements(), period: 10_000} 15 | # Add reporters as children of your supervision tree. 16 | # {Telemetry.Metrics.ConsoleReporter, metrics: metrics()} 17 | ] 18 | 19 | Supervisor.init(children, strategy: :one_for_one) 20 | end 21 | 22 | def metrics do 23 | [ 24 | # Phoenix Metrics 25 | summary("phoenix.endpoint.stop.duration", 26 | unit: {:native, :millisecond} 27 | ), 28 | summary("phoenix.router_dispatch.stop.duration", 29 | tags: [:route], 30 | unit: {:native, :millisecond} 31 | ), 32 | 33 | # VM Metrics 34 | summary("vm.memory.total", unit: {:byte, :kilobyte}), 35 | summary("vm.total_run_queue_lengths.total"), 36 | summary("vm.total_run_queue_lengths.cpu"), 37 | summary("vm.total_run_queue_lengths.io") 38 | ] 39 | end 40 | 41 | defp periodic_measurements do 42 | [ 43 | # A module, function and arguments to be invoked periodically. 44 | # This function must call :telemetry.execute/3 and a metric must be added above. 45 | # {MishkaApiWeb, :count_users, []} 46 | ] 47 | end 48 | end 49 | -------------------------------------------------------------------------------- /apps/mishka_api/lib/mishka_api_web/views/error_helpers.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaApiWeb.ErrorHelpers do 2 | @moduledoc """ 3 | Conveniences for translating and building error messages. 4 | """ 5 | 6 | @doc """ 7 | Translates an error message using gettext. 8 | """ 9 | def translate_error({msg, opts}) do 10 | # When using gettext, we typically pass the strings we want 11 | # to translate as a static argument: 12 | # 13 | # # Translate "is invalid" in the "errors" domain 14 | # dgettext("errors", "is invalid") 15 | # 16 | # # Translate the number of files with plural rules 17 | # dngettext("errors", "1 file", "%{count} files", count) 18 | # 19 | # Because the error messages we show in our forms and APIs 20 | # are defined inside Ecto, we need to translate them dynamically. 21 | # This requires us to call the Gettext module passing our gettext 22 | # backend as first argument. 23 | # 24 | # Note we use the "errors" domain, which means translations 25 | # should be written to the errors.po file. The :count option is 26 | # set by Ecto and indicates we should also apply plural rules. 27 | if count = opts[:count] do 28 | Gettext.dngettext(MishkaApiWeb.Gettext, "errors", msg, msg, count, opts) 29 | else 30 | Gettext.dgettext(MishkaApiWeb.Gettext, "errors", msg, opts) 31 | end 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /apps/mishka_api/lib/mishka_api_web/views/error_view.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaApiWeb.ErrorView do 2 | use MishkaApiWeb, :view 3 | 4 | # If you want to customize a particular status code 5 | # for a certain format, you may uncomment below. 6 | # def render("500.json", _assigns) do 7 | # %{errors: %{detail: "Internal Server Error"}} 8 | # end 9 | 10 | # By default, Phoenix returns the status message from 11 | # the template name. For example, "404.json" becomes 12 | # "Not Found". 13 | def template_not_found(template, _assigns) do 14 | %{errors: %{detail: Phoenix.Controller.status_message_from_template(template)}} 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /apps/mishka_api/test/mishka_api_web/views/error_view_test.exs: -------------------------------------------------------------------------------- 1 | defmodule MishkaApiWeb.ErrorViewTest do 2 | use MishkaApiWeb.ConnCase, async: true 3 | 4 | # Bring render/3 and render_to_string/3 for testing custom views 5 | import Phoenix.View 6 | 7 | test "renders 404.json" do 8 | assert render(MishkaApiWeb.ErrorView, "404.json", []) == %{errors: %{detail: "Not Found"}} 9 | end 10 | 11 | test "renders 500.json" do 12 | assert render(MishkaApiWeb.ErrorView, "500.json", []) == 13 | %{errors: %{detail: "Internal Server Error"}} 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /apps/mishka_api/test/support/channel_case.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaApiWeb.ChannelCase do 2 | @moduledoc """ 3 | This module defines the test case to be used by 4 | channel tests. 5 | 6 | Such tests rely on `Phoenix.ChannelTest` and also 7 | import other functionality to make it easier 8 | to build common data structures and query the data layer. 9 | 10 | Finally, if the test case interacts with the database, 11 | we enable the SQL sandbox, so changes done to the database 12 | are reverted at the end of every test. If you are using 13 | PostgreSQL, you can even run database tests asynchronously 14 | by setting `use MishkaApiWeb.ChannelCase, async: true`, although 15 | this option is not recommended for other databases. 16 | """ 17 | 18 | use ExUnit.CaseTemplate 19 | 20 | using do 21 | quote do 22 | # Import conveniences for testing with channels 23 | import Phoenix.ChannelTest 24 | import MishkaApiWeb.ChannelCase 25 | 26 | # The default endpoint for testing 27 | @endpoint MishkaApiWeb.Endpoint 28 | end 29 | end 30 | 31 | setup _tags do 32 | :ok 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /apps/mishka_api/test/support/conn_case.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaApiWeb.ConnCase do 2 | @moduledoc """ 3 | This module defines the test case to be used by 4 | tests that require setting up a connection. 5 | 6 | Such tests rely on `Phoenix.ConnTest` and also 7 | import other functionality to make it easier 8 | to build common data structures and query the data layer. 9 | 10 | Finally, if the test case interacts with the database, 11 | we enable the SQL sandbox, so changes done to the database 12 | are reverted at the end of every test. If you are using 13 | PostgreSQL, you can even run database tests asynchronously 14 | by setting `use MishkaApiWeb.ConnCase, async: true`, although 15 | this option is not recommended for other databases. 16 | """ 17 | 18 | use ExUnit.CaseTemplate 19 | 20 | using do 21 | quote do 22 | # Import conveniences for testing with connections 23 | import Plug.Conn 24 | import Phoenix.ConnTest 25 | import MishkaApiWeb.ConnCase 26 | 27 | alias MishkaApiWeb.Router.Helpers, as: Routes 28 | 29 | # The default endpoint for testing 30 | @endpoint MishkaApiWeb.Endpoint 31 | end 32 | end 33 | 34 | setup _tags do 35 | {:ok, conn: Phoenix.ConnTest.build_conn()} 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /apps/mishka_api/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /apps/mishka_content/.formatter.exs: -------------------------------------------------------------------------------- 1 | # Used by "mix format" 2 | [ 3 | inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] 4 | ] 5 | -------------------------------------------------------------------------------- /apps/mishka_content/.gitignore: -------------------------------------------------------------------------------- 1 | # The directory Mix will write compiled artifacts to. 2 | /_build/ 3 | 4 | # If you run "mix test --cover", coverage assets end up here. 5 | /cover/ 6 | 7 | # The directory Mix downloads your dependencies sources to. 8 | /deps/ 9 | 10 | # Where third-party dependencies like ExDoc output generated docs. 11 | /doc/ 12 | 13 | # Ignore .fetch files in case you like to edit your project deps locally. 14 | /.fetch 15 | 16 | # If the VM crashes, it generates a dump, let's ignore it too. 17 | erl_crash.dump 18 | 19 | # Also ignore archive artifacts (built via "mix archive.build"). 20 | *.ez 21 | 22 | # Ignore package tarball (built via "mix hex.build"). 23 | mishka_content-*.tar 24 | 25 | 26 | # Temporary files for e.g. tests 27 | /tmp 28 | -------------------------------------------------------------------------------- /apps/mishka_content/README.md: -------------------------------------------------------------------------------- 1 | # MishkaContent 2 | 3 | **TODO: Add description** 4 | 5 | ## Installation 6 | 7 | If [available in Hex](https://hex.pm/docs/publish), the package can be installed 8 | by adding `mishka_content` to your list of dependencies in `mix.exs`: 9 | 10 | ```elixir 11 | def deps do 12 | [ 13 | {:mishka_content, "~> 0.1.0"} 14 | ] 15 | end 16 | ``` 17 | 18 | Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc) 19 | and published on [HexDocs](https://hexdocs.pm). Once published, the docs can 20 | be found at [https://hexdocs.pm/mishka_content](https://hexdocs.pm/mishka_content). 21 | 22 | -------------------------------------------------------------------------------- /apps/mishka_content/lib/cache/bookmark_dynamic_supervisor.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaContent.Cache.BookmarkDynamicSupervisor do 2 | @spec start_job(list() | map() | tuple() | String.t()) :: 3 | :ignore | {:error, any} | {:ok, pid} | {:ok, pid, any} 4 | def start_job(args) do 5 | DynamicSupervisor.start_child( 6 | MishkaContent.Cache.BookmarkOtpRunner, 7 | {MishkaContent.Cache.BookmarkManagement, args} 8 | ) 9 | end 10 | 11 | @spec running_imports :: [any] 12 | 13 | def running_imports() do 14 | match_all = {:"$1", :"$2", :"$3"} 15 | guards = [{:==, :"$3", "user_bookmarks"}] 16 | map_result = [%{id: :"$1", pid: :"$2", type: :"$3"}] 17 | Registry.select(MishkaContent.Cache.BookmarkRegistry, [{match_all, guards, map_result}]) 18 | end 19 | 20 | @spec get_user_pid(String.t()) :: {:error, :get_user_pid} | {:ok, :get_user_pid, pid} 21 | 22 | def get_user_pid(user_id) do 23 | case Registry.lookup(MishkaContent.Cache.BookmarkRegistry, user_id) do 24 | [] -> {:error, :get_user_pid} 25 | [{pid, _type}] -> {:ok, :get_user_pid, pid} 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /apps/mishka_content/lib/cache/content_draft_dynamic_supervisor.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaContent.Cache.ContentDraftDynamicSupervisor do 2 | def start_job(args) do 3 | DynamicSupervisor.start_child( 4 | MishkaContent.Cache.ContentDraftOtpRunner, 5 | {MishkaContent.Cache.ContentDraftManagement, args} 6 | ) 7 | end 8 | 9 | def running_imports(section: section) do 10 | match_all = {:"$1", :"$2", :"$3"} 11 | guards = [{:==, :"$3", section}] 12 | map_result = [%{id: :"$1", pid: :"$2", section: :"$3"}] 13 | Registry.select(MishkaContent.Cache.ContentDraftRegistry, [{match_all, guards, map_result}]) 14 | end 15 | 16 | def get_draft_pid(id) do 17 | case Registry.lookup(MishkaContent.Cache.ContentDraftRegistry, id) do 18 | [] -> {:error, :get_draft_pid} 19 | [{pid, _type}] -> {:ok, :get_draft_pid, pid} 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /apps/mishka_content/lib/core_plugins/user/login/success_login.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaContent.CorePlugin.Login.SuccessLogin do 2 | alias MishkaInstaller.Reference.OnUserAfterLogin 3 | 4 | use MishkaInstaller.Hook, 5 | module: __MODULE__, 6 | behaviour: OnUserAfterLogin, 7 | event: :on_user_after_login, 8 | initial: [] 9 | 10 | @spec initial(list()) :: {:ok, OnUserAfterLogin.ref(), list()} 11 | def initial(args) do 12 | event = %PluginState{ 13 | name: "MishkaContent.CorePlugin.Login.SuccessLogin", 14 | event: Atom.to_string(@ref), 15 | priority: 2 16 | } 17 | 18 | Hook.register(event: event) 19 | {:ok, @ref, args} 20 | end 21 | 22 | @spec call(OnUserAfterLogin.t()) :: {:reply, OnUserAfterLogin.t()} 23 | def call(%OnUserAfterLogin{} = state) do 24 | create_user_activity(state.user_info, state.ip, state.endpoint) 25 | start_user_bookmarks(state.user_info.id) 26 | {:reply, state} 27 | end 28 | 29 | defp create_user_activity(user_info, user_ip, endpoint) do 30 | MishkaContent.General.Activity.create_activity_by_start_child( 31 | %{ 32 | type: if(endpoint == :html, do: "section", else: "internal_api"), 33 | section: "user", 34 | section_id: user_info.id, 35 | action: "auth", 36 | priority: "high", 37 | status: "info" 38 | }, 39 | %{user_action: "login", user_ip: MishkaInstaller.ip(user_ip), user_id: user_info.id} 40 | ) 41 | end 42 | 43 | def start_user_bookmarks(user_id) do 44 | Task.Supervisor.async_nolink( 45 | MishkaHtmlWeb.AuthController.DeleteCurrentTokenTaskSupervisor, 46 | fn -> 47 | MishkaContent.Cache.BookmarkDynamicSupervisor.start_job( 48 | id: user_id, 49 | type: "user_bookmarks" 50 | ) 51 | end 52 | ) 53 | end 54 | end 55 | -------------------------------------------------------------------------------- /apps/mishka_content/lib/core_plugins/user/login/success_logout.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaContent.CorePlugin.Login.SuccessLogout do 2 | alias MishkaInstaller.Reference.OnUserAfterLogout 3 | 4 | use MishkaInstaller.Hook, 5 | module: __MODULE__, 6 | behaviour: OnUserAfterLogout, 7 | event: :on_user_after_logout, 8 | initial: [] 9 | 10 | @spec initial(list()) :: {:ok, OnUserAfterLogout.ref(), list()} 11 | def initial(args) do 12 | event = %PluginState{ 13 | name: "MishkaContent.CorePlugin.Login.SuccessLogout", 14 | event: Atom.to_string(@ref), 15 | priority: 2 16 | } 17 | 18 | Hook.register(event: event) 19 | {:ok, @ref, args} 20 | end 21 | 22 | @spec call(OnUserAfterLogout.t()) :: {:reply, OnUserAfterLogout.t()} 23 | def call(%OnUserAfterLogout{} = state) do 24 | create_user_activity(state.user_id, state.ip, state.endpoint) 25 | {:reply, state} 26 | end 27 | 28 | defp create_user_activity(user_id, user_ip, endpoint) do 29 | MishkaContent.General.Activity.create_activity_by_start_child( 30 | %{ 31 | type: if(endpoint == :html, do: "section", else: "internal_api"), 32 | section: "user", 33 | section_id: nil, 34 | action: "auth", 35 | priority: "high", 36 | status: "info" 37 | }, 38 | %{user_action: "log_out", user_ip: MishkaInstaller.ip(user_ip), user_id: user_id} 39 | ) 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /apps/mishka_content/lib/core_plugins/user/role/success_add_role.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaContent.CorePlugin.UserRole.SuccessAddRole do 2 | alias MishkaInstaller.Reference.OnUserAfterSaveRole 3 | 4 | use MishkaInstaller.Hook, 5 | module: __MODULE__, 6 | behaviour: OnUserAfterSaveRole, 7 | event: :on_user_after_save_role, 8 | initial: [] 9 | 10 | @spec initial(list()) :: {:ok, OnUserAfterSaveRole.ref(), list()} 11 | def initial(args) do 12 | event = %PluginState{ 13 | name: "MishkaContent.CorePlugin.UserRole.SuccessAddRole", 14 | event: Atom.to_string(@ref), 15 | priority: 2 16 | } 17 | 18 | Hook.register(event: event) 19 | {:ok, @ref, args} 20 | end 21 | 22 | @spec call(OnUserAfterSaveRole.t()) :: {:reply, OnUserAfterSaveRole.t()} 23 | def call(%OnUserAfterSaveRole{} = state) do 24 | create_user_activity(state.role_id, state.ip, state.endpoint, state.conn) 25 | delete_user_bookmarks(state.conn) 26 | {:reply, state} 27 | end 28 | 29 | defp create_user_activity(role_id, user_ip, endpoint, socket) do 30 | MishkaContent.General.Activity.create_activity_by_start_child( 31 | %{ 32 | type: if(endpoint == :html, do: "section", else: "internal_api"), 33 | section: "role", 34 | section_id: role_id, 35 | action: "add", 36 | priority: "high", 37 | status: "info", 38 | user_id: socket.assigns.user_id 39 | }, 40 | %{user_action: "live_role_create", user_ip: MishkaInstaller.ip(user_ip)} 41 | ) 42 | end 43 | 44 | def delete_user_bookmarks(socket) do 45 | if(!is_nil(Map.get(socket.assigns, :draft_id))) do 46 | MishkaContent.Cache.ContentDraftManagement.delete_record(id: socket.assigns.draft_id) 47 | end 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /apps/mishka_content/lib/email/mailer.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaContent.Email.Mailer do 2 | use Bamboo.Mailer, otp_app: :mishka_content 3 | end 4 | -------------------------------------------------------------------------------- /apps/mishka_content/lib/general/user_notif_status.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaContent.General.UserNotifStatus do 2 | alias MishkaDatabase.Schema.MishkaContent.UserNotifStatus 3 | 4 | import Ecto.Query 5 | 6 | use MishkaDeveloperTools.DB.CRUD, 7 | module: UserNotifStatus, 8 | error_atom: :user_notif_status, 9 | repo: MishkaDatabase.Repo 10 | 11 | @type data_uuid() :: Ecto.UUID.t() 12 | @type record_input() :: map() 13 | @type error_tag() :: :subscription 14 | @type repo_data() :: Ecto.Schema.t() 15 | @type repo_error() :: Ecto.Changeset.t() 16 | 17 | @behaviour MishkaDeveloperTools.DB.CRUD 18 | 19 | @doc delegate_to: {MishkaDeveloperTools.DB.CRUD, :crud_add, 1} 20 | def create(attrs) do 21 | crud_add(attrs) 22 | end 23 | 24 | @doc delegate_to: {MishkaDeveloperTools.DB.CRUD, :crud_add, 1} 25 | def create(attrs, allowed_fields) do 26 | crud_add(attrs, allowed_fields) 27 | end 28 | 29 | @doc delegate_to: {MishkaDeveloperTools.DB.CRUD, :crud_edit, 1} 30 | def edit(attrs) do 31 | crud_edit(attrs) 32 | end 33 | 34 | @doc delegate_to: {MishkaDeveloperTools.DB.CRUD, :crud_edit, 1} 35 | def edit(attrs, allowed_fields) do 36 | crud_edit(attrs, allowed_fields) 37 | end 38 | 39 | @doc delegate_to: {MishkaDeveloperTools.DB.CRUD, :crud_delete, 1} 40 | def delete(id) do 41 | crud_delete(id) 42 | end 43 | 44 | @doc delegate_to: {MishkaDeveloperTools.DB.CRUD, :crud_get_record, 1} 45 | def show_by_id(id) do 46 | crud_get_record(id) 47 | end 48 | 49 | @spec user_read_or_skipped :: Ecto.Query.t() 50 | def user_read_or_skipped() do 51 | from(status in UserNotifStatus, 52 | select: %{notif_id: status.notif_id, user_id: status.user_id, status_type: status.type} 53 | ) 54 | end 55 | end 56 | -------------------------------------------------------------------------------- /apps/mishka_content/lib/mishka_content.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaContent do 2 | def db_content_activity_error(section, action, db_error) do 3 | MishkaContent.General.Activity.create_activity_by_task( 4 | %{ 5 | type: "db", 6 | section: section, 7 | section_id: nil, 8 | action: action, 9 | priority: "high", 10 | status: "error" 11 | }, 12 | %{ 13 | db_rescue_struct: db_error.__struct__, 14 | message: Map.get(db_error, :message), 15 | values: Map.get(db_error, :value), 16 | type: Map.get(db_error, :type) 17 | } 18 | ) 19 | end 20 | 21 | def get_size_of_words(string, count) when not is_nil(string) do 22 | string 23 | |> String.split(" ") 24 | |> Enum.with_index(fn element, index -> if index <= count, do: element end) 25 | |> Enum.reject(fn item -> is_nil(item) end) 26 | |> Enum.join(" ") 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /apps/mishka_content/lib/mishka_content/application.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaContent.Application do 2 | # See https://hexdocs.pm/elixir/Application.html 3 | # for more information on OTP Applications 4 | @moduledoc false 5 | 6 | alias MishkaContent.CorePlugin.{Login, Register, UserRole} 7 | use Application 8 | 9 | @impl true 10 | def start(_type, _args) do 11 | bookmark_runner_config = [ 12 | strategy: :one_for_one, 13 | name: MishkaContent.Cache.BookmarkOtpRunner 14 | ] 15 | 16 | content_draft_runner_config = [ 17 | strategy: :one_for_one, 18 | name: MishkaContent.Cache.ContentDraftOtpRunner 19 | ] 20 | 21 | children = [ 22 | {Task.Supervisor, name: MishkaContent.Email.EmailHelperTaskSupervisor}, 23 | {Task.Supervisor, name: MishkaContent.General.Notif}, 24 | {Task.Supervisor, name: MishkaContent.General.ActivityTaskSupervisor}, 25 | {Registry, keys: :unique, name: MishkaContent.Cache.BookmarkRegistry}, 26 | {Registry, keys: :unique, name: MishkaContent.Cache.ContentDraftRegistry}, 27 | {DynamicSupervisor, bookmark_runner_config}, 28 | {DynamicSupervisor, content_draft_runner_config}, 29 | %{id: Login.SuccessLogin, start: {Login.SuccessLogin, :start_link, [[]]}}, 30 | %{id: Login.SuccessLogout, start: {Login.SuccessLogout, :start_link, [[]]}}, 31 | %{id: Register.SuccessRegister, start: {Register.SuccessRegister, :start_link, [[]]}}, 32 | %{id: UserRole.SuccessAddRole, start: {UserRole.SuccessAddRole, :start_link, [[]]}} 33 | ] 34 | 35 | # See https://hexdocs.pm/elixir/Supervisor.html 36 | # for other strategies and supported options 37 | opts = [strategy: :one_for_one, name: MishkaContent.Supervisor] 38 | Supervisor.start_link(children, opts) 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /apps/mishka_content/lib/social/facebook.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaContent.Social.Facebook do 2 | end 3 | -------------------------------------------------------------------------------- /apps/mishka_content/lib/social/sender.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaContent.Social.Sender do 2 | end 3 | -------------------------------------------------------------------------------- /apps/mishka_content/lib/social/twitter.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaContent.Social.Twitter do 2 | end 3 | -------------------------------------------------------------------------------- /apps/mishka_content/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule MishkaContent.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :mishka_content, 7 | version: "0.0.2", 8 | build_path: "../../_build", 9 | config_path: "../../config/config.exs", 10 | deps_path: "../../deps", 11 | lockfile: "../../mix.lock", 12 | elixir: "~> 1.13", 13 | compilers: [:gettext | Mix.compilers()], 14 | start_permanent: Mix.env() == :prod, 15 | deps: deps(), 16 | xref: [ 17 | exclude: [MishkaUser.User, MishkaInstaller.Hook] 18 | ] 19 | ] 20 | end 21 | 22 | # Run "mix help compile.app" to learn about applications. 23 | def application do 24 | [ 25 | extra_applications: [ 26 | :logger, 27 | :ecto_sql, 28 | :ecto, 29 | :mishka_database, 30 | :phoenix_pubsub, 31 | :mishka_translator, 32 | :bamboo, 33 | :bamboo_smtp, 34 | :phoenix_html, 35 | :mishka_installer 36 | ], 37 | mod: {MishkaContent.Application, []} 38 | ] 39 | end 40 | 41 | # Run "mix help deps" to learn about dependencies. 42 | defp deps do 43 | [ 44 | {:mishka_installer, "~> 0.0.3"}, 45 | {:mishka_database, in_umbrella: true}, 46 | {:mishka_user, in_umbrella: true}, 47 | {:bamboo, "~> 2.2"}, 48 | {:bamboo_smtp, "~> 4.2"}, 49 | {:bamboo_phoenix, "~> 1.0"}, 50 | {:timex, "~> 3.7"}, 51 | {:mishka_translator, in_umbrella: true} 52 | ] 53 | end 54 | end 55 | -------------------------------------------------------------------------------- /apps/mishka_content/test/mishka_content_test.exs: -------------------------------------------------------------------------------- 1 | defmodule MishkaContentTest do 2 | use ExUnit.Case 3 | doctest MishkaContent 4 | end 5 | -------------------------------------------------------------------------------- /apps/mishka_content/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /apps/mishka_database/.formatter.exs: -------------------------------------------------------------------------------- 1 | # Used by "mix format" 2 | [ 3 | inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] 4 | ] 5 | -------------------------------------------------------------------------------- /apps/mishka_database/.gitignore: -------------------------------------------------------------------------------- 1 | # The directory Mix will write compiled artifacts to. 2 | /_build/ 3 | 4 | # If you run "mix test --cover", coverage assets end up here. 5 | /cover/ 6 | 7 | # The directory Mix downloads your dependencies sources to. 8 | /deps/ 9 | 10 | # Where third-party dependencies like ExDoc output generated docs. 11 | /doc/ 12 | 13 | # Ignore .fetch files in case you like to edit your project deps locally. 14 | /.fetch 15 | 16 | # If the VM crashes, it generates a dump, let's ignore it too. 17 | erl_crash.dump 18 | 19 | # Also ignore archive artifacts (built via "mix archive.build"). 20 | *.ez 21 | 22 | # Ignore package tarball (built via "mix hex.build"). 23 | mishka_database-*.tar 24 | 25 | 26 | # Temporary files for e.g. tests 27 | /tmp 28 | -------------------------------------------------------------------------------- /apps/mishka_database/README.md: -------------------------------------------------------------------------------- 1 | # MishkaDatabase 2 | 3 | **TODO: Add description** 4 | 5 | ## Installation 6 | 7 | If [available in Hex](https://hex.pm/docs/publish), the package can be installed 8 | by adding `mishka_database` to your list of dependencies in `mix.exs`: 9 | 10 | ```elixir 11 | def deps do 12 | [ 13 | {:mishka_database, "~> 0.1.0"} 14 | ] 15 | end 16 | ``` 17 | 18 | Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc) 19 | and published on [HexDocs](https://hexdocs.pm). Once published, the docs can 20 | be found at [https://hexdocs.pm/mishka_database](https://hexdocs.pm/mishka_database). 21 | 22 | -------------------------------------------------------------------------------- /apps/mishka_database/lib/mishka_database.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaDatabase do 2 | @moduledoc """ 3 | Documentation for `MishkaDatabase`. 4 | """ 5 | import Ecto.Changeset 6 | 7 | @spec translate_errors(Ecto.Changeset.t()) :: %{optional(atom) => [binary | map]} 8 | def translate_errors(changeset) do 9 | Ecto.Changeset.traverse_errors(changeset, fn {msg, opts} -> 10 | Enum.reduce(opts, msg, fn {key, value}, acc -> 11 | String.replace(acc, "%{#{key}}", to_string(value)) 12 | end) 13 | end) 14 | end 15 | 16 | @spec convert_string_map_to_atom_map(map) :: map 17 | def convert_string_map_to_atom_map(map) do 18 | map 19 | |> Map.new(fn {k, v} -> 20 | {String.to_existing_atom(k), v} 21 | end) 22 | end 23 | 24 | @spec validate_binary_id(Ecto.Changeset.t(), atom, any) :: Ecto.Changeset.t() 25 | def validate_binary_id(changeset, field, options \\ []) do 26 | validate_change(changeset, field, fn _, uuid -> 27 | case uuid(uuid) do 28 | {:ok, :uuid, _record_id} -> [] 29 | {:error, :uuid} -> [{field, options[:message] || "ID should be as a UUID type."}] 30 | end 31 | end) 32 | end 33 | 34 | @spec uuid(any) :: {:error, :uuid} | {:ok, :uuid, Ecto.UUID.t()} 35 | def uuid(id) do 36 | case Ecto.UUID.cast(id) do 37 | {:ok, record_id} -> {:ok, :uuid, record_id} 38 | _ -> {:error, :uuid} 39 | end 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /apps/mishka_database/lib/mishka_database/application.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaDatabase.Application do 2 | # See https://hexdocs.pm/elixir/Application.html 3 | # for more information on OTP Applications 4 | @moduledoc false 5 | 6 | use Application 7 | 8 | @impl true 9 | def start(_type, _args) do 10 | children = [ 11 | MishkaDatabase.Repo 12 | ] 13 | 14 | # See https://hexdocs.pm/elixir/Supervisor.html 15 | # for other strategies and supported options 16 | opts = [strategy: :one_for_one, name: MishkaDatabase.Supervisor, max_restarts: 100] 17 | Supervisor.start_link(children, opts) 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /apps/mishka_database/lib/mishka_database/repo.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaDatabase.Repo do 2 | use Ecto.Repo, 3 | otp_app: :mishka_database, 4 | adapter: Ecto.Adapters.Postgres 5 | 6 | use Scrivener, page_size: 20 7 | end 8 | -------------------------------------------------------------------------------- /apps/mishka_database/lib/schema/mishka_content/activity.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaDatabase.Schema.MishkaContent.Activity do 2 | use Ecto.Schema 3 | require MishkaTranslator.Gettext 4 | 5 | import Ecto.Changeset 6 | @primary_key {:id, :binary_id, autogenerate: true} 7 | @foreign_key_type :binary_id 8 | 9 | schema "activities" do 10 | field(:type, ActivitiesTypeEnum) 11 | field(:section, ActivitiesSection) 12 | field(:section_id, :binary_id, primary_key: false) 13 | field(:priority, ContentPriorityEnum) 14 | field(:status, ActivitiesStatusEnum) 15 | field(:action, ActivitiesAction) 16 | field(:extra, :map) 17 | 18 | timestamps(type: :utc_datetime) 19 | end 20 | 21 | @all_fields ~w(type section section_id priority status action extra)a 22 | @all_required ~w(type section priority status action)a 23 | 24 | @spec changeset(struct(), map()) :: Ecto.Changeset.t() 25 | def changeset(struct, params \\ %{}) do 26 | struct 27 | |> cast(params, @all_fields) 28 | |> validate_required(@all_required, 29 | message: 30 | MishkaTranslator.Gettext.dgettext("db_schema_content", "فیلد مذکور نمی تواند خالی باشد") 31 | ) 32 | |> MishkaDatabase.validate_binary_id(:section_id) 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /apps/mishka_database/lib/schema/mishka_content/blog_link.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaDatabase.Schema.MishkaContent.BlogLink do 2 | use Ecto.Schema 3 | 4 | require MishkaTranslator.Gettext 5 | import Ecto.Changeset 6 | @primary_key {:id, :binary_id, autogenerate: true} 7 | @foreign_key_type :binary_id 8 | 9 | schema "blog_links" do 10 | field(:short_description, :string) 11 | field(:status, ContentStatusEnum) 12 | field(:type, BlogLinkType) 13 | field(:title, :string) 14 | field(:link, :string) 15 | field(:short_link, :string) 16 | 17 | field(:robots, ContentRobotsEnum, default: :IndexFollow) 18 | 19 | field(:section_id, :binary_id) 20 | 21 | timestamps(type: :utc_datetime) 22 | end 23 | 24 | @all_fields ~w( 25 | short_description status type title link short_link robots section_id 26 | )a 27 | 28 | @all_required ~w( 29 | short_description status type title link robots section_id 30 | )a 31 | 32 | @spec changeset(struct(), map()) :: Ecto.Changeset.t() 33 | def changeset(struct, params \\ %{}) do 34 | struct 35 | |> cast(params, @all_fields) 36 | |> validate_required(@all_required, 37 | message: 38 | MishkaTranslator.Gettext.dgettext("db_schema_content", "فیلد مذکور نمی تواند خالی باشد") 39 | ) 40 | |> MishkaDatabase.validate_binary_id(:section_id) 41 | |> unique_constraint(:short_link, 42 | name: :index_blog_links_on_short_link, 43 | message: 44 | MishkaTranslator.Gettext.dgettext( 45 | "db_schema_content", 46 | "این لینک کوتاه از قبل انتخاب شده است. لطفا لینک دیگری را وارد کنید." 47 | ) 48 | ) 49 | end 50 | end 51 | -------------------------------------------------------------------------------- /apps/mishka_database/lib/schema/mishka_content/bookmark.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaDatabase.Schema.MishkaContent.Bookmark do 2 | use Ecto.Schema 3 | 4 | require MishkaTranslator.Gettext 5 | import Ecto.Changeset 6 | @primary_key {:id, :binary_id, autogenerate: true} 7 | @foreign_key_type :binary_id 8 | 9 | schema "bookmarks" do 10 | field(:status, ContentStatusEnum, default: :active) 11 | field(:section, BookmarkSection) 12 | field(:section_id, :binary_id, primary_key: false) 13 | field(:extra, :map) 14 | 15 | belongs_to(:users, MishkaDatabase.Schema.MishkaUser.User, 16 | foreign_key: :user_id, 17 | type: :binary_id 18 | ) 19 | 20 | timestamps(type: :utc_datetime) 21 | end 22 | 23 | @all_fields ~w(status section section_id extra user_id)a 24 | @all_required ~w(status section section_id user_id)a 25 | 26 | @spec changeset(struct(), map()) :: Ecto.Changeset.t() 27 | def changeset(struct, params \\ %{}) do 28 | struct 29 | |> cast(params, @all_fields) 30 | |> validate_required(@all_required, 31 | message: 32 | MishkaTranslator.Gettext.dgettext("db_schema_content", "فیلد مذکور نمی تواند خالی باشد") 33 | ) 34 | |> MishkaDatabase.validate_binary_id(:user_id) 35 | |> MishkaDatabase.validate_binary_id(:section_id) 36 | |> foreign_key_constraint(:user_id, 37 | message: 38 | MishkaTranslator.Gettext.dgettext( 39 | "db_schema_content", 40 | "ممکن است فیلد مذکور اشتباه باشد یا برای حذف آن اگر اقدام می کنید برای آن وابستگی وجود داشته باشد" 41 | ) 42 | ) 43 | |> unique_constraint(:section, 44 | name: :index_bookmarks_on_section_and_section_id_and_user_id, 45 | message: 46 | MishkaTranslator.Gettext.dgettext("db_schema_content", "این بخش قبلا بوکمارک شده است") 47 | ) 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /apps/mishka_database/lib/schema/mishka_content/content_schema_enum.ex: -------------------------------------------------------------------------------- 1 | import EctoEnum 2 | defenum(ContentStatusEnum, inactive: 0, active: 1, archived: 2, soft_delete: 3) 3 | defenum(ContentPriorityEnum, none: 0, low: 1, medium: 2, high: 3, featured: 4) 4 | defenum(ContentRobotsEnum, IndexFollow: 0, IndexNoFollow: 1, NoIndexFollow: 2, NoIndexNoFollow: 3) 5 | defenum(CategoryVisibility, show: 0, invisibel: 1, test_show: 2, test_invisibel: 3) 6 | defenum(PostVisibility, show: 0, invisibel: 1, test_show: 2, test_invisibel: 3) 7 | defenum(CommentSection, blog_post: 0) 8 | defenum(SubscriptionSection, blog_post: 0, blog_category: 1) 9 | defenum(BlogLinkType, bottom: 0, inside: 1, featured: 2) 10 | defenum(ActivitiesStatusEnum, error: 0, info: 1, warning: 2, report: 3, throw: 4, exit: 5) 11 | 12 | defenum(ActivitiesTypeEnum, 13 | section: 0, 14 | email: 1, 15 | internal_api: 2, 16 | external_api: 3, 17 | html_router: 4, 18 | api_router: 5, 19 | db: 6, 20 | plugin: 7 21 | ) 22 | 23 | defenum(ActivitiesSection, 24 | blog_post: 0, 25 | blog_category: 1, 26 | comment: 2, 27 | tag: 3, 28 | other: 4, 29 | blog_author: 5, 30 | blog_post_like: 6, 31 | blog_tag_mapper: 7, 32 | blog_link: 8, 33 | blog_tag: 9, 34 | activity: 10, 35 | bookmark: 11, 36 | comment_like: 12, 37 | notif: 13, 38 | subscription: 14, 39 | setting: 15, 40 | permission: 16, 41 | role: 17, 42 | user_role: 18, 43 | identity: 19, 44 | user: 20 45 | ) 46 | 47 | defenum(ActivitiesAction, 48 | add: 0, 49 | edit: 1, 50 | delete: 2, 51 | destroy: 3, 52 | read: 4, 53 | send_request: 5, 54 | receive_request: 6, 55 | other: 7, 56 | auth: 8 57 | ) 58 | 59 | defenum(BookmarkSection, blog_post: 0) 60 | defenum(NotifSection, blog_post: 0, admin: 1, user_only: 3, public: 4) 61 | defenum(NotifStatusType, read: 0, skipped: 1) 62 | defenum(NotifType, client: 0, admin: 1) 63 | defenum(NotifTarget, all: 0, mobile: 1, android: 2, ios: 3, cli: 4) 64 | -------------------------------------------------------------------------------- /apps/mishka_database/lib/schema/mishka_content/subscription.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaDatabase.Schema.MishkaContent.Subscription do 2 | use Ecto.Schema 3 | 4 | require MishkaTranslator.Gettext 5 | import Ecto.Changeset 6 | @primary_key {:id, :binary_id, autogenerate: true} 7 | @foreign_key_type :binary_id 8 | 9 | schema "subscriptions" do 10 | field(:status, ContentStatusEnum, default: :active) 11 | field(:section, SubscriptionSection) 12 | field(:section_id, :binary_id, primary_key: false) 13 | field(:expire_time, :utc_datetime) 14 | field(:extra, :map) 15 | 16 | belongs_to(:users, MishkaDatabase.Schema.MishkaUser.User, 17 | foreign_key: :user_id, 18 | type: :binary_id 19 | ) 20 | 21 | timestamps(type: :utc_datetime) 22 | end 23 | 24 | @all_fields ~w(status section section_id expire_time extra user_id)a 25 | @all_required ~w(status section section_id user_id)a 26 | 27 | @spec changeset(struct(), map()) :: Ecto.Changeset.t() 28 | def changeset(struct, params \\ %{}) do 29 | struct 30 | |> cast(params, @all_fields) 31 | |> validate_required(@all_required, 32 | message: 33 | MishkaTranslator.Gettext.dgettext("db_schema_content", "فیلد مذکور نمی تواند خالی باشد") 34 | ) 35 | |> MishkaDatabase.validate_binary_id(:section_id) 36 | |> MishkaDatabase.validate_binary_id(:user_id) 37 | |> foreign_key_constraint(:user_id, 38 | message: 39 | MishkaTranslator.Gettext.dgettext( 40 | "db_schema_content", 41 | "ممکن است فیلد مذکور اشتباه باشد یا برای حذف آن اگر اقدام می کنید برای آن وابستگی وجود داشته باشد" 42 | ) 43 | ) 44 | |> unique_constraint(:section, 45 | name: :index_subscriptions_on_section_and_section_id_and_user_id, 46 | message: 47 | MishkaTranslator.Gettext.dgettext( 48 | "db_schema_content", 49 | "شما از قبل در این بخش مشترک شده اید." 50 | ) 51 | ) 52 | end 53 | end 54 | -------------------------------------------------------------------------------- /apps/mishka_database/lib/schema/mishka_user/permission.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaDatabase.Schema.MishkaUser.Permission do 2 | use Ecto.Schema 3 | require MishkaTranslator.Gettext 4 | import Ecto.Changeset 5 | @primary_key {:id, :binary_id, autogenerate: true} 6 | @foreign_key_type :binary_id 7 | 8 | schema "permissions" do 9 | field(:value, :string) 10 | 11 | belongs_to(:roles, MishkaDatabase.Schema.MishkaUser.Role, 12 | foreign_key: :role_id, 13 | type: :binary_id 14 | ) 15 | 16 | timestamps(type: :utc_datetime) 17 | end 18 | 19 | @spec changeset(struct(), map()) :: Ecto.Changeset.t() 20 | def changeset(struct, params \\ %{}) do 21 | struct 22 | |> cast(params, [:value, :role_id]) 23 | |> validate_required([:value, :role_id], 24 | message: 25 | MishkaTranslator.Gettext.dgettext("db_schema_user", "فیلد مذکور نمی تواند خالی باشد") 26 | ) 27 | |> MishkaDatabase.validate_binary_id(:role_id) 28 | |> foreign_key_constraint(:role_id, 29 | message: 30 | MishkaTranslator.Gettext.dgettext( 31 | "db_schema_user", 32 | "ممکن است فیلد مذکور اشتباه باشد یا برای حذف آن اگر اقدام می کنید برای آن وابستگی وجود داشته باشد" 33 | ) 34 | ) 35 | |> unique_constraint(:value, 36 | name: :index_permissions_on_value_and_role_id, 37 | message: 38 | MishkaTranslator.Gettext.dgettext( 39 | "db_schema_user", 40 | "این سطح دسترسی از قبل برای نقش مذکور اضافه شده است" 41 | ) 42 | ) 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /apps/mishka_database/lib/schema/mishka_user/role.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaDatabase.Schema.MishkaUser.Role do 2 | use Ecto.Schema 3 | require MishkaTranslator.Gettext 4 | import Ecto.Changeset 5 | @primary_key {:id, :binary_id, autogenerate: true} 6 | @foreign_key_type :binary_id 7 | 8 | schema "roles" do 9 | field(:name, :string) 10 | field(:display_name, :string) 11 | 12 | has_many(:users_roles, MishkaDatabase.Schema.MishkaUser.UserRole, 13 | foreign_key: :role_id, 14 | on_delete: :delete_all 15 | ) 16 | 17 | has_many(:permissions, MishkaDatabase.Schema.MishkaUser.Permission, 18 | foreign_key: :role_id, 19 | on_delete: :delete_all 20 | ) 21 | 22 | timestamps(type: :utc_datetime) 23 | end 24 | 25 | @spec changeset(struct(), map()) :: Ecto.Changeset.t() 26 | def changeset(struct, params \\ %{}) do 27 | struct 28 | |> cast(params, [:name, :display_name]) 29 | |> validate_required([:name, :display_name], 30 | message: 31 | MishkaTranslator.Gettext.dgettext("db_schema_user", "فیلد مذکور نمی تواند خالی باشد") 32 | ) 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /apps/mishka_database/lib/schema/mishka_user/user_schema_enum.ex: -------------------------------------------------------------------------------- 1 | import EctoEnum 2 | 3 | defenum(UserIdentityProviderEnum, self: 0, google: 1, github: 2, facebook: 3, twitter: 4, apple: 5) 4 | 5 | defenum(UserStatusEnum, registered: 0, active: 1, inactive: 2, archived: 3) 6 | defenum(UserTokenTypeEnum, refresh: 0, access: 1) 7 | -------------------------------------------------------------------------------- /apps/mishka_database/lib/schema/mishka_user/user_token.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaDatabase.Schema.MishkaUser.UserToken do 2 | use Ecto.Schema 3 | 4 | require MishkaTranslator.Gettext 5 | import Ecto.Changeset 6 | @primary_key {:id, :binary_id, autogenerate: false} 7 | @foreign_key_type :binary_id 8 | 9 | schema "user_tokens" do 10 | field(:token, :string) 11 | field(:type, UserTokenTypeEnum) 12 | field(:expire_time, :utc_datetime) 13 | field(:extra, :map) 14 | 15 | belongs_to(:users, MishkaDatabase.Schema.MishkaUser.User, 16 | foreign_key: :user_id, 17 | type: :binary_id 18 | ) 19 | 20 | timestamps(type: :utc_datetime) 21 | end 22 | 23 | @all_fields ~w(id token type expire_time extra user_id)a 24 | @spec changeset(struct(), map()) :: Ecto.Changeset.t() 25 | def changeset(struct, params \\ %{}) do 26 | struct 27 | |> cast(params, @all_fields) 28 | |> validate_required(@all_fields, 29 | message: 30 | MishkaTranslator.Gettext.dgettext("db_schema_user", "فیلد مذکور نمی تواند خالی باشد") 31 | ) 32 | |> foreign_key_constraint(:user_id, 33 | message: 34 | MishkaTranslator.Gettext.dgettext( 35 | "db_schema_user", 36 | "ممکن است فیلد مذکور اشتباه باشد یا برای حذف آن اگر اقدام می کنید برای آن وابستگی وجود داشته باشد" 37 | ) 38 | ) 39 | |> unique_constraint(:token, 40 | name: :index_token_on_user_tokens, 41 | message: 42 | MishkaTranslator.Gettext.dgettext( 43 | "db_schema_user", 44 | "این ایمیل از قبل در سیستم ثبت شده است." 45 | ) 46 | ) 47 | end 48 | end 49 | -------------------------------------------------------------------------------- /apps/mishka_database/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule MishkaDatabase.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :mishka_database, 7 | version: "0.0.2", 8 | build_path: "../../_build", 9 | config_path: "../../config/config.exs", 10 | deps_path: "../../deps", 11 | aliases: aliases(), 12 | lockfile: "../../mix.lock", 13 | elixir: "~> 1.13", 14 | compilers: [:gettext | Mix.compilers()], 15 | start_permanent: Mix.env() == :prod, 16 | deps: deps() 17 | ] 18 | end 19 | 20 | # Run "mix help compile.app" to learn about applications. 21 | def application do 22 | [ 23 | extra_applications: [:logger, :mishka_translator, :phoenix_pubsub], 24 | mod: {MishkaDatabase.Application, []} 25 | ] 26 | end 27 | 28 | # Run "mix help deps" to learn about dependencies. 29 | defp deps do 30 | [ 31 | {:mishka_developer_tools, "~> 0.0.6"}, 32 | {:comeonin, "~> 5.3"}, 33 | {:bcrypt_elixir, "~> 2.3"}, 34 | {:ecto_enum, "~> 1.4"}, 35 | {:jason, "~> 1.2"}, 36 | {:scrivener_ecto, "~> 2.7"}, 37 | {:mishka_translator, in_umbrella: true} 38 | ] 39 | end 40 | 41 | defp aliases do 42 | [ 43 | test: ["ecto.create --quiet", "ecto.migrate", "test"] 44 | ] 45 | end 46 | end 47 | -------------------------------------------------------------------------------- /apps/mishka_database/priv/repo/migrations/20210111193110_users.exs: -------------------------------------------------------------------------------- 1 | defmodule MishkaDatabase.Repo.Migrations.Users do 2 | use Ecto.Migration 3 | 4 | def change do 5 | create table(:users, primary_key: false) do 6 | add(:id, :uuid, primary_key: true) 7 | add(:full_name, :string, size: 60, null: false) 8 | add(:username, :string, size: 20, null: true, unique: true) 9 | add(:email, :string, null: false, unique: true) 10 | add(:password_hash, :string, null: true) 11 | add(:status, :integer, null: false) 12 | add(:unconfirmed_email, :string, size: 120, null: true, unique: true) 13 | timestamps() 14 | end 15 | create( 16 | index(:users, [:email], 17 | name: :index_users_on_email, 18 | unique: true 19 | ) 20 | ) 21 | create( 22 | index(:users, [:unconfirmed_email], 23 | name: :index_users_on_verified_email, 24 | unique: true 25 | ) 26 | ) 27 | create( 28 | index(:users, [:username], 29 | name: :index_users_on_username, 30 | unique: true 31 | ) 32 | ) 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /apps/mishka_database/priv/repo/migrations/20210328064612_identities.exs: -------------------------------------------------------------------------------- 1 | defmodule MishkaDatabase.Repo.Migrations.Identities do 2 | use Ecto.Migration 3 | 4 | def change do 5 | create table(:identities, primary_key: false) do 6 | add(:id, :uuid, primary_key: true) 7 | 8 | 9 | add(:provider_uid, :string, null: true) 10 | add(:token, :string, null: true) 11 | add(:identity_provider, :integer, null: false) 12 | 13 | add(:user_id, references(:users, on_delete: :nothing, type: :uuid)) 14 | timestamps() 15 | end 16 | create( 17 | index(:identities, [:provider_uid, :identity_provider], 18 | name: :index_identities_on_provider_uid_and_identity_provider, 19 | unique: true 20 | ) 21 | ) 22 | 23 | create( 24 | index(:identities, [:user_id, :identity_provider], 25 | name: :index_identities_on_user_id_and_identity_provider, 26 | unique: true 27 | ) 28 | ) 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /apps/mishka_database/priv/repo/migrations/20210328103652_roles.exs: -------------------------------------------------------------------------------- 1 | defmodule MishkaDatabase.Repo.Migrations.Roles do 2 | use Ecto.Migration 3 | 4 | def change do 5 | create table(:roles, primary_key: false) do 6 | add(:id, :uuid, primary_key: true) 7 | 8 | 9 | add(:name, :string, null: false) 10 | add(:display_name, :string, null: false) 11 | 12 | timestamps() 13 | end 14 | create( 15 | index(:roles, [:display_name], 16 | name: :index_roles_on_display_name, 17 | unique: true 18 | ) 19 | ) 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /apps/mishka_database/priv/repo/migrations/20210328103704_permissions.exs: -------------------------------------------------------------------------------- 1 | defmodule MishkaDatabase.Repo.Migrations.Permissions do 2 | use Ecto.Migration 3 | 4 | def change do 5 | create table(:permissions, primary_key: false) do 6 | add(:id, :uuid, primary_key: true) 7 | 8 | 9 | add(:value, :string, null: false) 10 | add(:role_id, references(:roles, on_delete: :delete_all, type: :uuid), null: false) 11 | timestamps() 12 | end 13 | create( 14 | index(:permissions, [:value, :role_id], 15 | name: :index_permissions_on_value_and_role_id, 16 | unique: true 17 | ) 18 | ) 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /apps/mishka_database/priv/repo/migrations/20210330072832_blog_tags.exs: -------------------------------------------------------------------------------- 1 | defmodule MishkaDatabase.Repo.Migrations.BlogTags do 2 | use Ecto.Migration 3 | 4 | def change do 5 | create table(:blog_tags, primary_key: false) do 6 | add(:id, :uuid, primary_key: true) 7 | add(:title, :string, size: 200, null: false) 8 | 9 | 10 | add(:alias_link, :string, size: 200, null: false) 11 | add(:meta_keywords, :string, size: 200, null: true) 12 | add(:meta_description, :string, size: 164, null: true) 13 | add(:custom_title, :string, size: 200, null: true) 14 | add(:robots, :integer, null: false) 15 | 16 | timestamps() 17 | end 18 | create( 19 | index(:blog_tags, [:alias_link], 20 | # concurrently: true, 21 | name: :index_blog_tags_on_alias_link, 22 | unique: true 23 | ) 24 | ) 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /apps/mishka_database/priv/repo/migrations/20210330072837_blog_tags_mappers.exs: -------------------------------------------------------------------------------- 1 | defmodule MishkaDatabase.Repo.Migrations.BlogTagsMappers do 2 | use Ecto.Migration 3 | 4 | def change do 5 | create table(:blog_tags_mappers, primary_key: false) do 6 | add(:id, :uuid, primary_key: true) 7 | 8 | add(:post_id, references(:blog_posts, on_delete: :nothing, type: :uuid)) 9 | add(:tag_id, references(:blog_tags, on_delete: :nothing, type: :uuid)) 10 | 11 | timestamps() 12 | end 13 | create( 14 | index(:blog_tags_mappers, [:post_id, :tag_id], 15 | name: :index_blog_tags_mappers_on_post_id_and_tag_id, 16 | unique: true 17 | ) 18 | ) 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /apps/mishka_database/priv/repo/migrations/20210330132342_blog_authors.exs: -------------------------------------------------------------------------------- 1 | defmodule MishkaDatabase.Repo.Migrations.BlogAuthors do 2 | use Ecto.Migration 3 | 4 | def change do 5 | create table(:blog_authors, primary_key: false) do 6 | add(:id, :uuid, primary_key: true) 7 | 8 | add(:post_id, references(:blog_posts, on_delete: :nothing, type: :uuid)) 9 | add(:user_id, references(:users, on_delete: :nothing, type: :uuid)) 10 | 11 | timestamps() 12 | end 13 | create( 14 | index(:blog_authors, [:post_id, :user_id], 15 | name: :index_blog_authors_on_post_id_and_user_id, 16 | unique: true 17 | ) 18 | ) 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /apps/mishka_database/priv/repo/migrations/20210330132407_blog_likes.exs: -------------------------------------------------------------------------------- 1 | defmodule MishkaDatabase.Repo.Migrations.BlogLikes do 2 | use Ecto.Migration 3 | 4 | def change do 5 | create table(:blog_likes, primary_key: false) do 6 | add(:id, :uuid, primary_key: true) 7 | 8 | add(:post_id, references(:blog_posts, on_delete: :nothing, type: :uuid)) 9 | add(:user_id, references(:users, on_delete: :nothing, type: :uuid)) 10 | 11 | timestamps() 12 | end 13 | create( 14 | index(:blog_likes, [:post_id, :user_id], 15 | name: :index_blog_likes_on_post_id_and_user_id, 16 | unique: true 17 | ) 18 | ) 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /apps/mishka_database/priv/repo/migrations/20210330141536_blog_links.exs: -------------------------------------------------------------------------------- 1 | defmodule MishkaDatabase.Repo.Migrations.BlogLinks do 2 | use Ecto.Migration 3 | 4 | def change do 5 | create table(:blog_links, primary_key: false) do 6 | add(:id, :uuid, primary_key: true) 7 | 8 | add(:short_description, :text, null: true) 9 | add(:status, :integer, null: false) 10 | add(:type, :integer, null: false) 11 | add(:title, :string, size: 200, null: false) 12 | add(:link, :string, size: 350, null: false) 13 | add(:short_link, :string, size: 350, null: true) 14 | 15 | add(:section_id, :uuid, primary_key: false, null: false) 16 | 17 | add(:robots, :integer, null: false) 18 | 19 | timestamps() 20 | end 21 | create( 22 | index(:blog_links, [:short_link], 23 | name: :index_blog_links_on_short_link, 24 | unique: true 25 | ) 26 | ) 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /apps/mishka_database/priv/repo/migrations/20210330142326_subscriptions.exs: -------------------------------------------------------------------------------- 1 | defmodule MishkaDatabase.Repo.Migrations.Subscriptions do 2 | use Ecto.Migration 3 | 4 | def change do 5 | create table(:subscriptions, primary_key: false) do 6 | add(:id, :uuid, primary_key: true) 7 | 8 | add(:status, :integer, null: false) 9 | add(:section, :integer, null: false, null: false) 10 | add(:section_id, :uuid, primary_key: false, null: false) 11 | add(:expire_time, :utc_datetime, null: true) 12 | add(:extra, :map, null: true) 13 | 14 | add(:user_id, references(:users, on_delete: :nothing, type: :uuid)) 15 | timestamps() 16 | end 17 | create( 18 | index(:subscriptions, [:section, :section_id, :user_id], 19 | name: :index_subscriptions_on_section_and_section_id_and_user_id, 20 | unique: true 21 | ) 22 | ) 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /apps/mishka_database/priv/repo/migrations/20210330142350_bookmarks.exs: -------------------------------------------------------------------------------- 1 | defmodule MishkaDatabase.Repo.Migrations.Bookmarks do 2 | use Ecto.Migration 3 | 4 | def change do 5 | create table(:bookmarks, primary_key: false) do 6 | add(:id, :uuid, primary_key: true) 7 | 8 | add(:status, :integer, null: false) 9 | add(:section, :integer, null: false, null: false) 10 | add(:section_id, :uuid, primary_key: false, null: false) 11 | add(:extra, :map, null: true) 12 | 13 | add(:user_id, references(:users, on_delete: :nothing, type: :uuid)) 14 | timestamps() 15 | end 16 | create( 17 | index(:bookmarks, [:section, :section_id, :user_id], 18 | name: :index_bookmarks_on_section_and_section_id_and_user_id, 19 | unique: true 20 | ) 21 | ) 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /apps/mishka_database/priv/repo/migrations/20210330142430_notifs.exs: -------------------------------------------------------------------------------- 1 | defmodule MishkaDatabase.Repo.Migrations.Notifs do 2 | use Ecto.Migration 3 | 4 | def change do 5 | create table(:notifs, primary_key: false) do 6 | 7 | add(:id, :uuid, primary_key: true) 8 | 9 | add(:status, :integer, null: false) 10 | add(:section, :integer, null: false) 11 | add(:section_id, :uuid, primary_key: false, null: true) 12 | add(:type, :integer, null: false) 13 | add(:target, :integer, null: false) 14 | add(:title, :string, size: 350, null: false) 15 | add(:description, :text, null: false) 16 | add(:expire_time, :utc_datetime, null: true) 17 | add(:extra, :map, null: true) 18 | 19 | add(:user_id, references(:users, on_delete: :nothing, type: :uuid)) 20 | 21 | timestamps() 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /apps/mishka_database/priv/repo/migrations/20210330162305_comments.exs: -------------------------------------------------------------------------------- 1 | defmodule MishkaDatabase.Repo.Migrations.Comments do 2 | use Ecto.Migration 3 | 4 | def change do 5 | create table(:comments, primary_key: false) do 6 | add(:id, :uuid, primary_key: true) 7 | 8 | # comment basic info 9 | add(:description, :text, null: false) 10 | add(:status, :integer, null: false) 11 | add(:priority, :integer, null: false) 12 | add(:section, :integer, null: false, null: false) 13 | add(:section_id, :uuid, primary_key: false, null: false) 14 | add(:sub, :uuid, primary_key: false, null: true) 15 | 16 | add(:user_id, references(:users, on_delete: :nothing, type: :uuid)) 17 | timestamps() 18 | end 19 | 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /apps/mishka_database/priv/repo/migrations/20210330224243_comments_likes.exs: -------------------------------------------------------------------------------- 1 | defmodule MishkaDatabase.Repo.Migrations.CommentsLikes do 2 | use Ecto.Migration 3 | 4 | def change do 5 | create table(:comments_likes, primary_key: false) do 6 | add(:id, :uuid, primary_key: true) 7 | 8 | add(:user_id, references(:users, on_delete: :nothing, type: :uuid)) 9 | add(:comment_id, references(:comments, on_delete: :nothing, type: :uuid)) 10 | 11 | 12 | timestamps() 13 | end 14 | create( 15 | index(:comments_likes, [:user_id, :comment_id], 16 | name: :index_comments_on_likes, 17 | unique: true 18 | ) 19 | ) 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /apps/mishka_database/priv/repo/migrations/20210402080613_users_roles.exs: -------------------------------------------------------------------------------- 1 | defmodule MishkaDatabase.Repo.Migrations.UsersRoles do 2 | use Ecto.Migration 3 | 4 | def change do 5 | create table(:users_roles, primary_key: false) do 6 | add(:id, :uuid, primary_key: true) 7 | 8 | add(:role_id, references(:roles, type: :uuid), null: false) 9 | add(:user_id, references(:users, type: :uuid), null: false) 10 | timestamps() 11 | end 12 | create( 13 | index(:users_roles, [:role_id, :user_id], 14 | name: :index_users_roles_on_role_id_and_user_id, 15 | unique: true 16 | ) 17 | ) 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /apps/mishka_database/priv/repo/migrations/20211005180905_user_notif_statuses.exs: -------------------------------------------------------------------------------- 1 | defmodule MishkaDatabase.Repo.Migrations.UserNotifStatuses do 2 | use Ecto.Migration 3 | 4 | def change do 5 | create table(:user_notif_statuses, primary_key: false) do 6 | 7 | add(:id, :uuid, primary_key: true) 8 | add(:type, :integer, null: false) 9 | add(:user_id, references(:users, on_delete: :nothing, type: :uuid), null: false) 10 | add(:notif_id, references(:notifs, on_delete: :delete_all, type: :uuid), null: false) 11 | 12 | timestamps() 13 | end 14 | create( 15 | index(:user_notif_statuses, [:user_id, :notif_id], 16 | name: :index_user_notif_on_user_notif_statuses, 17 | unique: true 18 | ) 19 | ) 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /apps/mishka_database/priv/repo/migrations/20220626144233_user_tokens.exs: -------------------------------------------------------------------------------- 1 | defmodule MishkaDatabase.Repo.Migrations.UserTokens do 2 | use Ecto.Migration 3 | 4 | def change do 5 | create table(:user_tokens, primary_key: false) do 6 | add(:id, :uuid, primary_key: true) 7 | add(:token, :text, null: false) 8 | add(:type, :integer, null: false) 9 | add(:expire_time, :utc_datetime, null: false) 10 | add(:extra, :map, null: false) 11 | 12 | add(:user_id, references(:users, on_delete: :nothing, type: :uuid), null: false) 13 | timestamps() 14 | end 15 | create( 16 | index(:user_tokens, [:token], 17 | name: :index_token_on_user_tokens, 18 | unique: true 19 | ) 20 | ) 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /apps/mishka_database/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /apps/mishka_file/.formatter.exs: -------------------------------------------------------------------------------- 1 | # Used by "mix format" 2 | [ 3 | inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] 4 | ] 5 | -------------------------------------------------------------------------------- /apps/mishka_file/.gitignore: -------------------------------------------------------------------------------- 1 | # The directory Mix will write compiled artifacts to. 2 | /_build/ 3 | 4 | # If you run "mix test --cover", coverage assets end up here. 5 | /cover/ 6 | 7 | # The directory Mix downloads your dependencies sources to. 8 | /deps/ 9 | 10 | # Where third-party dependencies like ExDoc output generated docs. 11 | /doc/ 12 | 13 | # Ignore .fetch files in case you like to edit your project deps locally. 14 | /.fetch 15 | 16 | # If the VM crashes, it generates a dump, let's ignore it too. 17 | erl_crash.dump 18 | 19 | # Also ignore archive artifacts (built via "mix archive.build"). 20 | *.ez 21 | 22 | # Ignore package tarball (built via "mix hex.build"). 23 | mishka_file-*.tar 24 | 25 | 26 | # Temporary files for e.g. tests 27 | /tmp 28 | -------------------------------------------------------------------------------- /apps/mishka_file/README.md: -------------------------------------------------------------------------------- 1 | # MishkaFile 2 | 3 | **TODO: Add description** 4 | 5 | ## Installation 6 | 7 | If [available in Hex](https://hex.pm/docs/publish), the package can be installed 8 | by adding `mishka_file` to your list of dependencies in `mix.exs`: 9 | 10 | ```elixir 11 | def deps do 12 | [ 13 | {:mishka_file, "~> 0.1.0"} 14 | ] 15 | end 16 | ``` 17 | 18 | Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc) 19 | and published on [HexDocs](https://hexdocs.pm). Once published, the docs can 20 | be found at [https://hexdocs.pm/mishka_file](https://hexdocs.pm/mishka_file). 21 | 22 | -------------------------------------------------------------------------------- /apps/mishka_file/lib/mishka_file.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaFile do 2 | end 3 | -------------------------------------------------------------------------------- /apps/mishka_file/lib/mishka_file/application.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaFile.Application do 2 | # See https://hexdocs.pm/elixir/Application.html 3 | # for more information on OTP Applications 4 | @moduledoc false 5 | 6 | use Application 7 | 8 | @impl true 9 | def start(_type, _args) do 10 | children = [ 11 | # Starts a worker by calling: MishkaFile.Worker.start_link(arg) 12 | # {MishkaFile.Worker, arg} 13 | ] 14 | 15 | # See https://hexdocs.pm/elixir/Supervisor.html 16 | # for other strategies and supported options 17 | opts = [strategy: :one_for_one, name: MishkaFile.Supervisor] 18 | Supervisor.start_link(children, opts) 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /apps/mishka_file/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule MishkaFile.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :mishka_file, 7 | version: "0.0.2", 8 | build_path: "../../_build", 9 | config_path: "../../config/config.exs", 10 | deps_path: "../../deps", 11 | lockfile: "../../mix.lock", 12 | elixir: "~> 1.13", 13 | compilers: [:gettext | Mix.compilers()], 14 | start_permanent: Mix.env() == :prod, 15 | deps: deps() 16 | ] 17 | end 18 | 19 | # Run "mix help compile.app" to learn about applications. 20 | def application do 21 | [ 22 | extra_applications: [:logger, :mishka_translator], 23 | mod: {MishkaFile.Application, []} 24 | ] 25 | end 26 | 27 | # Run "mix help deps" to learn about dependencies. 28 | defp deps do 29 | [ 30 | {:mishka_translator, in_umbrella: true} 31 | ] 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /apps/mishka_file/test/mishka_file_test.exs: -------------------------------------------------------------------------------- 1 | defmodule MishkaFileTest do 2 | use ExUnit.Case 3 | doctest MishkaFile 4 | end 5 | -------------------------------------------------------------------------------- /apps/mishka_file/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /apps/mishka_html/.formatter.exs: -------------------------------------------------------------------------------- 1 | [ 2 | import_deps: [:phoenix], 3 | inputs: ["*.{ex,exs}", "{config,lib,test}/**/*.{ex,exs}"] 4 | ] 5 | -------------------------------------------------------------------------------- /apps/mishka_html/.gitignore: -------------------------------------------------------------------------------- 1 | # The directory Mix will write compiled artifacts to. 2 | /_build/ 3 | 4 | # If you run "mix test --cover", coverage assets end up here. 5 | /cover/ 6 | 7 | # The directory Mix downloads your dependencies sources to. 8 | /deps/ 9 | 10 | # Where 3rd-party dependencies like ExDoc output generated docs. 11 | /doc/ 12 | 13 | # Ignore .fetch files in case you like to edit your project deps locally. 14 | /.fetch 15 | 16 | # If the VM crashes, it generates a dump, let's ignore it too. 17 | erl_crash.dump 18 | 19 | # Also ignore archive artifacts (built via "mix archive.build"). 20 | *.ez 21 | 22 | # Ignore package tarball (built via "mix hex.build"). 23 | mishka_html-*.tar 24 | 25 | # If NPM crashes, it generates a log, let's ignore it too. 26 | npm-debug.log 27 | 28 | # The directory NPM downloads your dependencies sources to. 29 | /assets/node_modules/ 30 | 31 | # Since we are building assets from assets/, 32 | # we ignore priv/static. You may want to comment 33 | # this depending on your deployment strategy. 34 | /priv/static/assets/ 35 | /priv/static/uploads/ 36 | -------------------------------------------------------------------------------- /apps/mishka_html/README.md: -------------------------------------------------------------------------------- 1 | # MishkaHtml 2 | 3 | To start your Phoenix server: 4 | 5 | * Install dependencies with `mix deps.get` 6 | * Install Node.js dependencies with `npm install` inside the `assets` directory 7 | * Start Phoenix endpoint with `mix phx.server` 8 | 9 | Now you can visit [`localhost:4000`](http://localhost:4000) from your browser. 10 | 11 | Ready to run in production? Please [check our deployment guides](https://hexdocs.pm/phoenix/deployment.html). 12 | 13 | ## Learn more 14 | 15 | * Official website: https://www.phoenixframework.org/ 16 | * Guides: https://hexdocs.pm/phoenix/overview.html 17 | * Docs: https://hexdocs.pm/phoenix 18 | * Forum: https://elixirforum.com/c/phoenix-forum 19 | * Source: https://github.com/phoenixframework/phoenix 20 | -------------------------------------------------------------------------------- /apps/mishka_html/assets/static/css/font.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'Iconly-bulk'; 3 | src: url('../fonts/Iconly-bulk.eot?7ldoi4'); 4 | src: url('../fonts/Iconly-bulk.eot?7ldoi4#iefix') format('embedded-opentype'), 5 | url('../fonts/Iconly-bulk.ttf?7ldoi4') format('truetype'), 6 | url('../fonts/Iconly-bulk.woff?7ldoi4') format('woff'), 7 | url('../fonts/Iconly-bulk.svg?7ldoi4#Iconly-bulk') format('svg'); 8 | font-weight: normal; 9 | font-style: normal; 10 | font-display: block; 11 | } 12 | 13 | @font-face { 14 | font-family: 'Vazir-Regular'; 15 | src: url('../fonts/Vazir-Regular.eot?7ldoi4'); 16 | src: url('../fonts/Vazir-Regular.eot?7ldoi4#iefix') format('embedded-opentype'), 17 | url('../fonts/Vazir-Regular.ttf?7ldoi4') format('truetype'), 18 | url('../fonts/Vazir-Regular.woff?7ldoi4') format('woff'); 19 | 20 | 21 | font-weight: normal; 22 | font-style: normal; 23 | font-display: block; 24 | } -------------------------------------------------------------------------------- /apps/mishka_html/assets/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahryarjb/mishka-cms/45563d985f98217f57e25829375835d93f540a6e/apps/mishka_html/assets/static/favicon.ico -------------------------------------------------------------------------------- /apps/mishka_html/assets/static/fonts/Iconly-bulk.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahryarjb/mishka-cms/45563d985f98217f57e25829375835d93f540a6e/apps/mishka_html/assets/static/fonts/Iconly-bulk.eot -------------------------------------------------------------------------------- /apps/mishka_html/assets/static/fonts/Iconly-bulk.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahryarjb/mishka-cms/45563d985f98217f57e25829375835d93f540a6e/apps/mishka_html/assets/static/fonts/Iconly-bulk.ttf -------------------------------------------------------------------------------- /apps/mishka_html/assets/static/fonts/Iconly-bulk.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahryarjb/mishka-cms/45563d985f98217f57e25829375835d93f540a6e/apps/mishka_html/assets/static/fonts/Iconly-bulk.woff -------------------------------------------------------------------------------- /apps/mishka_html/assets/static/fonts/Iconly-light.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahryarjb/mishka-cms/45563d985f98217f57e25829375835d93f540a6e/apps/mishka_html/assets/static/fonts/Iconly-light.eot -------------------------------------------------------------------------------- /apps/mishka_html/assets/static/fonts/Vazir-Regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahryarjb/mishka-cms/45563d985f98217f57e25829375835d93f540a6e/apps/mishka_html/assets/static/fonts/Vazir-Regular.eot -------------------------------------------------------------------------------- /apps/mishka_html/assets/static/fonts/Vazir-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahryarjb/mishka-cms/45563d985f98217f57e25829375835d93f540a6e/apps/mishka_html/assets/static/fonts/Vazir-Regular.ttf -------------------------------------------------------------------------------- /apps/mishka_html/assets/static/fonts/Vazir-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahryarjb/mishka-cms/45563d985f98217f57e25829375835d93f540a6e/apps/mishka_html/assets/static/fonts/Vazir-Regular.woff -------------------------------------------------------------------------------- /apps/mishka_html/assets/static/fonts/Vazir-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahryarjb/mishka-cms/45563d985f98217f57e25829375835d93f540a6e/apps/mishka_html/assets/static/fonts/Vazir-Regular.woff2 -------------------------------------------------------------------------------- /apps/mishka_html/assets/static/images/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahryarjb/mishka-cms/45563d985f98217f57e25829375835d93f540a6e/apps/mishka_html/assets/static/images/1.jpg -------------------------------------------------------------------------------- /apps/mishka_html/assets/static/images/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahryarjb/mishka-cms/45563d985f98217f57e25829375835d93f540a6e/apps/mishka_html/assets/static/images/2.jpg -------------------------------------------------------------------------------- /apps/mishka_html/assets/static/images/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahryarjb/mishka-cms/45563d985f98217f57e25829375835d93f540a6e/apps/mishka_html/assets/static/images/3.jpg -------------------------------------------------------------------------------- /apps/mishka_html/assets/static/images/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahryarjb/mishka-cms/45563d985f98217f57e25829375835d93f540a6e/apps/mishka_html/assets/static/images/4.jpg -------------------------------------------------------------------------------- /apps/mishka_html/assets/static/images/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahryarjb/mishka-cms/45563d985f98217f57e25829375835d93f540a6e/apps/mishka_html/assets/static/images/5.jpg -------------------------------------------------------------------------------- /apps/mishka_html/assets/static/images/icons8-login-as-user-80.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahryarjb/mishka-cms/45563d985f98217f57e25829375835d93f540a6e/apps/mishka_html/assets/static/images/icons8-login-as-user-80.png -------------------------------------------------------------------------------- /apps/mishka_html/assets/static/images/mylogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahryarjb/mishka-cms/45563d985f98217f57e25829375835d93f540a6e/apps/mishka_html/assets/static/images/mylogo.png -------------------------------------------------------------------------------- /apps/mishka_html/assets/static/images/no-user-image.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahryarjb/mishka-cms/45563d985f98217f57e25829375835d93f540a6e/apps/mishka_html/assets/static/images/no-user-image.jpg -------------------------------------------------------------------------------- /apps/mishka_html/assets/static/js/check_editor_extended.js: -------------------------------------------------------------------------------- 1 | const classCheckEditor = require('./ckeditor'); 2 | 3 | classCheckEditor.A.prototype.cleanup = function() { 4 | 5 | } 6 | 7 | module.exports = classCheckEditor; -------------------------------------------------------------------------------- /apps/mishka_html/assets/static/js/translations/af.js: -------------------------------------------------------------------------------- 1 | (function(e){const n=e["af"]=e["af"]||{};n.dictionary=Object.assign(n.dictionary||{},{"Align center":"Belyn in die middel","Align left":"Belyn links","Align right":"Belyn regs","Block quote":"Blok-aanhaling",Bold:"Vetgedruk",Cancel:"Kanselleer",Code:"Kode",Italic:"Skuinsgedruk",Justify:"Belyn beide kante","Remove color":"","Remove Format":"Verwyder formatering","Restore default":"",Save:"Berg","Show more items":"",Strikethrough:"Deurgetrek","Text alignment":"Teksbelyning","Text alignment toolbar":"",Underline:"Onderstreep"});n.getPluralForm=function(e){return e!=1}})(window.CKEDITOR_TRANSLATIONS||(window.CKEDITOR_TRANSLATIONS={})); -------------------------------------------------------------------------------- /apps/mishka_html/assets/static/js/translations/ca.js: -------------------------------------------------------------------------------- 1 | (function(a){const e=a["ca"]=a["ca"]||{};e.dictionary=Object.assign(e.dictionary||{},{"Align center":"Alineació centre","Align left":"Alineació esquerra","Align right":"Alineació dreta",Big:"Gran","Block quote":"Cita de bloc","Blue marker":"Marcador blau",Bold:"Negreta",Cancel:"Cancel·lar","Choose heading":"Escull capçalera",Code:"Codi",Default:"Predeterminada","Document colors":"","Font Background Color":"","Font Color":"","Font Size":"Mida de la font","Green marker":"Marcador verd","Green pen":"Bolígraf verd",Heading:"Capçalera","Heading 1":"Capçalera 1","Heading 2":"Capçalera 2","Heading 3":"Capçalera 3","Heading 4":"","Heading 5":"","Heading 6":"",Highlight:"Destacat",Huge:"Molt gran",Italic:"Cursiva",Justify:"Justificar",Paragraph:"Pàrraf","Pink marker":"Marcador rosa","Red pen":"Marcador vermell","Remove color":"","Remove highlight":"Esborrar destacat","Restore default":"",Save:"Desar","Show more items":"",Small:"Peita",Strikethrough:"Marcat","Text alignment":"Alineació text","Text alignment toolbar":"","Text highlight toolbar":"",Tiny:"Molt petita",Underline:"Subrallat","Yellow marker":"Marcador groc"});e.getPluralForm=function(a){return a!=1}})(window.CKEDITOR_TRANSLATIONS||(window.CKEDITOR_TRANSLATIONS={})); -------------------------------------------------------------------------------- /apps/mishka_html/assets/static/js/translations/gu.js: -------------------------------------------------------------------------------- 1 | (function(n){const o=n["gu"]=n["gu"]||{};o.dictionary=Object.assign(o.dictionary||{},{"Block quote":" વિચાર ટાંકો",Bold:"ઘાટુ - બોલ્ડ્",Code:"",Italic:"ત્રાંસુ - ઇટલિક્",Strikethrough:"",Underline:"નીચે લિટી - અન્ડરલાઇન્"});o.getPluralForm=function(n){return n!=1}})(window.CKEDITOR_TRANSLATIONS||(window.CKEDITOR_TRANSLATIONS={})); -------------------------------------------------------------------------------- /apps/mishka_html/assets/static/js/translations/kk.js: -------------------------------------------------------------------------------- 1 | (function(n){const t=n["kk"]=n["kk"]||{};t.dictionary=Object.assign(t.dictionary||{},{"Align center":"Ортадан туралау","Align left":"Солға туралау","Align right":"Оңға туралау",Justify:"","Text alignment":"Мәтінді туралау","Text alignment toolbar":"Мәтінді туралау құралдар тақтасы"});t.getPluralForm=function(n){return n!=1}})(window.CKEDITOR_TRANSLATIONS||(window.CKEDITOR_TRANSLATIONS={})); -------------------------------------------------------------------------------- /apps/mishka_html/assets/static/js/translations/oc.js: -------------------------------------------------------------------------------- 1 | (function(o){const e=o["oc"]=o["oc"]||{};e.dictionary=Object.assign(e.dictionary||{},{Bold:"Gras",Cancel:"Anullar",Code:"",Italic:"Italica","Remove color":"","Restore default":"",Save:"Enregistrar","Show more items":"",Strikethrough:"",Underline:""});e.getPluralForm=function(o){return o>1}})(window.CKEDITOR_TRANSLATIONS||(window.CKEDITOR_TRANSLATIONS={})); -------------------------------------------------------------------------------- /apps/mishka_html/assets/static/js/translations/si.js: -------------------------------------------------------------------------------- 1 | (function(e){const t=e["si"]=e["si"]||{};t.dictionary=Object.assign(t.dictionary||{},{Bold:"තදකුරු","Break text":"","Bulleted List":"බුලටිත ලැයිස්තුව","Bulleted list styles toolbar":"","Centered image":"","Change image text alternative":"",Circle:"",Code:"",Decimal:"","Decimal with leading zero":"",Disc:"","Enter image caption":"","Full size image":"","Image resize list":"","Image toolbar":"","image widget":"","In line":"",Insert:"","Insert image":"පින්තූරය ඇතුල් කරන්න","Insert image via URL":"",Italic:"ඇලකුරු","Left aligned image":"","Lower-latin":"","Lower–roman":"","Numbered List":"අංකිත ලැයිස්තුව","Numbered list styles toolbar":"",Original:"",Redo:"නැවත කරන්න","Resize image":"","Resize image to %0":"","Resize image to the original size":"","Right aligned image":"","Side image":"",Square:"",Strikethrough:"","Text alternative":"","To-do List":"","Toggle the circle list style":"","Toggle the decimal list style":"","Toggle the decimal with leading zero list style":"","Toggle the disc list style":"","Toggle the lower–latin list style":"","Toggle the lower–roman list style":"","Toggle the square list style":"","Toggle the upper–latin list style":"","Toggle the upper–roman list style":"",Underline:"",Undo:"අහෝසි කරන්න",Update:"","Update image URL":"","Upload failed":"උඩුගත කිරීම අසාර්ථක විය","Upper-latin":"","Upper-roman":"","Wrap text":""});t.getPluralForm=function(e){return e!=1}})(window.CKEDITOR_TRANSLATIONS||(window.CKEDITOR_TRANSLATIONS={})); -------------------------------------------------------------------------------- /apps/mishka_html/assets/static/js/translations/tt.js: -------------------------------------------------------------------------------- 1 | (function(o){const t=o["tt"]=o["tt"]||{};t.dictionary=Object.assign(t.dictionary||{},{Bold:"Калын",Cancel:"",Code:"Код",Italic:"",Redo:"Кабатла","Remove color":"","Restore default":"",Save:"Сакла","Show more items":"",Strikethrough:"",Underline:"",Undo:""});t.getPluralForm=function(o){return 0}})(window.CKEDITOR_TRANSLATIONS||(window.CKEDITOR_TRANSLATIONS={})); -------------------------------------------------------------------------------- /apps/mishka_html/assets/static/robots.txt: -------------------------------------------------------------------------------- 1 | # See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file 2 | # 3 | # To ban all spiders from the entire site uncomment the next two lines: 4 | # User-agent: * 5 | # Disallow: / 6 | -------------------------------------------------------------------------------- /apps/mishka_html/lib/mishka_html/application.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaHtml.Application do 2 | # See https://hexdocs.pm/elixir/Application.html 3 | # for more information on OTP Applications 4 | @moduledoc false 5 | 6 | use Application 7 | 8 | def start(_type, _args) do 9 | children = [ 10 | # Start the Telemetry supervisor 11 | MishkaHtmlWeb.Telemetry, 12 | # Start the PubSub system 13 | {Phoenix.PubSub, name: MishkaHtml.PubSub}, 14 | {Task.Supervisor, name: MishkaHtmlWeb.AuthController.DeleteCurrentTokenTaskSupervisor}, 15 | # Start the Endpoint (http/https) 16 | MishkaHtmlWeb.Endpoint 17 | ] 18 | 19 | # See https://hexdocs.pm/elixir/Supervisor.html 20 | # for other strategies and supported options 21 | opts = [strategy: :one_for_one, name: MishkaHtml.Supervisor] 22 | Supervisor.start_link(children, opts) 23 | end 24 | 25 | # Tell Phoenix to update the endpoint configuration 26 | # whenever the application is updated. 27 | def config_change(changed, _new, removed) do 28 | MishkaHtmlWeb.Endpoint.config_change(changed, removed) 29 | :ok 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /apps/mishka_html/lib/mishka_html/plug/not_login_plug.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaHtml.Plug.NotLoginPlug do 2 | import Plug.Conn 3 | use MishkaHtmlWeb, :controller 4 | alias MishkaUser.Token.CurrentPhoenixToken 5 | alias MishkaHtmlWeb.Router.Helpers, as: Routes 6 | require MishkaTranslator.Gettext 7 | 8 | def init(default), do: default 9 | 10 | def call(conn, _default) do 11 | user_ip = to_string(:inet_parse.ntoa(conn.remote_ip)) 12 | 13 | case CurrentPhoenixToken.verify_token(get_session(conn, :current_token), :current) do 14 | {:ok, :verify_token, :current, current_token_info} -> 15 | on_user_login_failure(conn, user_ip, {:ok, :verify_token, :current, current_token_info}).conn 16 | 17 | conn 18 | |> put_flash( 19 | :error, 20 | MishkaTranslator.Gettext.dgettext("html_auth", "شما از قبل وارد سایت شده اید.") 21 | ) 22 | |> redirect(to: Routes.live_path(conn, MishkaHtmlWeb.HomeLive)) 23 | |> halt() 24 | 25 | _ -> 26 | conn 27 | end 28 | end 29 | 30 | defp on_user_login_failure(conn, user_ip, error) do 31 | state = %MishkaInstaller.Reference.OnUserLoginFailure{ 32 | conn: conn, 33 | ip: user_ip, 34 | endpoint: :html, 35 | error: error 36 | } 37 | 38 | MishkaInstaller.Hook.call(event: "on_user_login_failure", state: state) 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /apps/mishka_html/lib/mishka_html_web/channels/user_socket.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaHtmlWeb.UserSocket do 2 | use Phoenix.Socket 3 | 4 | ## Channels 5 | # channel "room:*", MishkaHtmlWeb.RoomChannel 6 | 7 | # Socket params are passed from the client and can 8 | # be used to verify and authenticate a user. After 9 | # verification, you can put default assigns into 10 | # the socket that will be set for all channels, ie 11 | # 12 | # {:ok, assign(socket, :user_id, verified_user_id)} 13 | # 14 | # To deny connection, return `:error`. 15 | # 16 | # See `Phoenix.Token` documentation for examples in 17 | # performing token verification on connect. 18 | @impl true 19 | def connect(_params, socket, _connect_info) do 20 | {:ok, socket} 21 | end 22 | 23 | # Socket id's are topics that allow you to identify all sockets for a given user: 24 | # 25 | # def id(socket), do: "user_socket:#{socket.assigns.user_id}" 26 | # 27 | # Would allow you to broadcast a "disconnect" event and terminate 28 | # all active sockets and channels for a given user: 29 | # 30 | # MishkaHtmlWeb.Endpoint.broadcast("user_socket:#{user.id}", "disconnect", %{}) 31 | # 32 | # Returning `nil` makes this socket anonymous. 33 | @impl true 34 | def id(_socket), do: nil 35 | end 36 | -------------------------------------------------------------------------------- /apps/mishka_html/lib/mishka_html_web/endpoint.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaHtmlWeb.Endpoint do 2 | use Phoenix.Endpoint, otp_app: :mishka_html 3 | 4 | # The session will be stored in the cookie and signed, 5 | # this means its contents can be read but not tampered with. 6 | # Set :encryption_salt if you would also like to encrypt it. 7 | @session_options [ 8 | store: :cookie, 9 | key: "_mishka_html_key", 10 | signing_salt: "zKj1Tpml" 11 | ] 12 | 13 | socket "/socket", MishkaHtmlWeb.UserSocket, 14 | websocket: true, 15 | longpoll: false 16 | 17 | socket "/live", Phoenix.LiveView.Socket, 18 | websocket: [connect_info: [:peer_data, session: @session_options]] 19 | 20 | # Serve at "/" the static files from "priv/static" directory. 21 | # 22 | # You should set gzip to true if you are running phx.digest 23 | # when deploying your static files in production. 24 | plug Plug.Static, 25 | at: "/", 26 | from: :mishka_html, 27 | gzip: false, 28 | # only: ~w( css fonts images js favicon.ico robots.txt) 29 | only: ~w(uploads assets fonts images favicon.ico robots.txt css js) 30 | 31 | # Code reloading can be explicitly enabled under the 32 | # :code_reloader configuration of your endpoint. 33 | if code_reloading? do 34 | socket "/phoenix/live_reload/socket", Phoenix.LiveReloader.Socket 35 | plug Phoenix.LiveReloader 36 | plug Phoenix.CodeReloader 37 | end 38 | 39 | plug Phoenix.LiveDashboard.RequestLogger, 40 | param_key: "request_logger", 41 | cookie_key: "request_logger" 42 | 43 | plug Plug.RequestId 44 | plug Plug.Telemetry, event_prefix: [:phoenix, :endpoint] 45 | 46 | plug Plug.Parsers, 47 | parsers: [:urlencoded, :multipart, :json], 48 | pass: ["*/*"], 49 | json_decoder: Phoenix.json_library() 50 | 51 | plug Plug.MethodOverride 52 | plug Plug.Head 53 | plug Plug.Session, @session_options 54 | plug MishkaHtmlWeb.Router 55 | end 56 | -------------------------------------------------------------------------------- /apps/mishka_html/lib/mishka_html_web/gettext.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaHtmlWeb.Gettext do 2 | @moduledoc """ 3 | A module providing Internationalization with a gettext-based API. 4 | 5 | By using [Gettext](https://hexdocs.pm/gettext), 6 | your module gains a set of macros for translations, for example: 7 | 8 | import MishkaHtmlWeb.Gettext 9 | 10 | # Simple translation 11 | gettext("Here is the string to translate") 12 | 13 | # Plural translation 14 | ngettext("Here is the string to translate", 15 | "Here are the strings to translate", 16 | 3) 17 | 18 | # Domain-based translation 19 | dgettext("errors", "Here is the error message to translate") 20 | 21 | See the [Gettext Docs](https://hexdocs.pm/gettext) for detailed usage. 22 | """ 23 | use Gettext, otp_app: :mishka_html 24 | end 25 | -------------------------------------------------------------------------------- /apps/mishka_html/lib/mishka_html_web/live/admin_activity_live.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaHtmlWeb.AdminActivityLive do 2 | use MishkaHtmlWeb, :live_view 3 | 4 | alias MishkaContent.General.Activity 5 | 6 | use MishkaHtml.Helpers.LiveCRUD, 7 | module: MishkaContent.Blog.BlogLink, 8 | redirect: __MODULE__, 9 | router: Routes 10 | 11 | @impl true 12 | def render(assigns) do 13 | Phoenix.View.render(MishkaHtmlWeb.AdminActivityView, "admin_activity_live.html", assigns) 14 | end 15 | 16 | @impl true 17 | def mount(%{"id" => id}, session, socket) do 18 | socket = 19 | case Activity.show_by_id(id) do 20 | {:error, :get_record_by_id, _error_atom} -> 21 | socket 22 | |> put_flash( 23 | :warning, 24 | MishkaTranslator.Gettext.dgettext( 25 | "html_live", 26 | "چنین لاگی وجود ندارد یا ممکن است از قبل حذف شده باشد." 27 | ) 28 | ) 29 | |> push_redirect(to: Routes.live_path(socket, MishkaHtmlWeb.AdminActivitiesLive)) 30 | 31 | {:ok, :get_record_by_id, _error_atom, record} -> 32 | Process.send_after(self(), :menu, 100) 33 | 34 | socket 35 | |> assign( 36 | activity: record, 37 | user_id: Map.get(session, "user_id"), 38 | body_color: "#a29ac3cf" 39 | ) 40 | end 41 | 42 | {:ok, socket} 43 | end 44 | 45 | selected_menue("MishkaHtmlWeb.AdminLogLive") 46 | end 47 | -------------------------------------------------------------------------------- /apps/mishka_html/lib/mishka_html_web/live/admin_media_manager_live.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaHtmlWeb.AdminMediaManagerLive do 2 | use MishkaHtmlWeb, :live_view 3 | 4 | use MishkaHtml.Helpers.LiveCRUD, 5 | module: MishkaContent.Blog.BlogLink, 6 | redirect: __MODULE__, 7 | router: Routes 8 | 9 | @impl true 10 | def render(assigns) do 11 | Phoenix.View.render( 12 | MishkaHtmlWeb.AdminMediaManagerView, 13 | "admin_media_manager_live.html", 14 | assigns 15 | ) 16 | end 17 | 18 | @impl true 19 | def mount(_params, session, socket) do 20 | Process.send_after(self(), :menu, 100) 21 | 22 | {:ok, 23 | assign(socket, 24 | user_id: Map.get(session, "user_id"), 25 | page_title: MishkaTranslator.Gettext.dgettext("html_live", "مدیریت فایل ها"), 26 | body_color: "#a29ac3cf" 27 | )} 28 | end 29 | 30 | selected_menue("MishkaHtmlWeb.AdminMediaManagerLive") 31 | end 32 | -------------------------------------------------------------------------------- /apps/mishka_html/lib/mishka_html_web/live/admin_seo_live.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaHtmlWeb.AdminSeoLive do 2 | use MishkaHtmlWeb, :live_view 3 | 4 | use MishkaHtml.Helpers.LiveCRUD, 5 | module: MishkaContent.Blog.BlogLink, 6 | redirect: __MODULE__, 7 | router: Routes 8 | 9 | @impl true 10 | def render(assigns) do 11 | Phoenix.View.render(MishkaHtmlWeb.AdminSeoView, "admin_seo_live.html", assigns) 12 | end 13 | 14 | @impl true 15 | def mount(_params, session, socket) do 16 | Process.send_after(self(), :menu, 100) 17 | 18 | {:ok, 19 | assign(socket, 20 | user_id: Map.get(session, "user_id"), 21 | page_title: MishkaTranslator.Gettext.dgettext("html_live", "تنظیمات سئو"), 22 | body_color: "#a29ac3cf" 23 | )} 24 | end 25 | 26 | selected_menue("MishkaHtmlWeb.AdminSeoLive") 27 | end 28 | -------------------------------------------------------------------------------- /apps/mishka_html/lib/mishka_html_web/live/components/admin/dashboard/admin_dashboard_last_users_component.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaHtmlWeb.Admin.Dashboard.LastUsersComponent do 2 | use MishkaHtmlWeb, :live_component 3 | 4 | def render(assigns) do 5 | ~H""" 6 |
7 |

8 |
9 | 10 | 11 | 12 | <%= MishkaTranslator.Gettext.dgettext("html_live_component", "آخرین ثبت نام ها") %> 13 |
14 |

15 |
16 | 21 |
22 | <%= live_redirect MishkaTranslator.Gettext.dgettext("html_live_templates", "نمایش همه کاربران"), to: Routes.live_path(@socket, MishkaHtmlWeb.AdminUsersLive), class: "col-sm-12 btn btn-outline-secondary btn-lg" %> 23 |
24 | """ 25 | end 26 | 27 | def handle_event("close", _, socket) do 28 | {:noreply, push_patch(socket, to: socket.assigns.return_to)} 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /apps/mishka_html/lib/mishka_html_web/live/components/admin/dashboard/admin_last_blog_posts_component.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaHtmlWeb.Admin.Dashboard.LastBlogPostsComponent do 2 | use MishkaHtmlWeb, :live_component 3 | 4 | def render(assigns) do 5 | ~H""" 6 |
7 |
8 |

<%= MishkaTranslator.Gettext.dgettext("html_live_component", "آخرین مطالب منتشر شده:") %>

9 | 10 |
11 | <%= for post <- @posts do %> 12 |
13 | <%= live_redirect to: Routes.live_path(@socket, MishkaHtmlWeb.AdminBlogPostLive, id: post.id), replace: false do %> 14 | {post.title} 15 | <% end %> 16 |
17 | <% end %> 18 |
19 | 20 |
21 |
22 | """ 23 | end 24 | 25 | def handle_event("close", _, socket) do 26 | {:noreply, push_patch(socket, to: socket.assigns.return_to)} 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /apps/mishka_html/lib/mishka_html_web/live/components/admin/dashboard/admin_last_notif_component.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaHtmlWeb.Admin.Dashboard.LastNotifComponent do 2 | use MishkaHtmlWeb, :live_component 3 | 4 | def render(assigns) do 5 | ~H""" 6 |
7 |

8 |
9 | 10 | 11 | <%= MishkaTranslator.Gettext.dgettext("html_live_component", "آخرین اطلاع رسانی ها") %> 12 |
13 |
    14 | <%= for notif <- @notifs do %> 15 |
  • <%= notif_summary(notif) %>
  • 16 | <% end %> 17 |
18 | <%= live_redirect MishkaTranslator.Gettext.dgettext("html_live_templates", "نمایش همه اعلانات"), to: Routes.live_path(@socket, MishkaHtmlWeb.AdminBlogNotifsLive), class: "col-sm-12 btn btn-outline-secondary btn-lg" %> 19 |
20 |

21 |
22 | """ 23 | end 24 | 25 | def handle_event("close", _, socket) do 26 | {:noreply, push_patch(socket, to: socket.assigns.return_to)} 27 | end 28 | 29 | def notif_summary(notif) when notif.section == :public, 30 | do: MishkaTranslator.Gettext.dgettext("html_live_templates", "اطلاع رسانی عمومی و انبوه") 31 | 32 | def notif_summary(notif) when notif.section == :user_only, 33 | do: MishkaTranslator.Gettext.dgettext("html_live_templates", "اطلاع رسانی مختص به کاربر") 34 | 35 | def notif_summary(notif) when notif.section == :admin, 36 | do: MishkaTranslator.Gettext.dgettext("html_live_templates", "اطلاع رسانی مخصوص مدیریت") 37 | 38 | def notif_summary(_notif), 39 | do: MishkaTranslator.Gettext.dgettext("html_live_templates", "اطلاع رسانی مخصوص به بخش") 40 | end 41 | -------------------------------------------------------------------------------- /apps/mishka_html/lib/mishka_html_web/live/components/admin/form/add_field_component.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaHtmlWeb.Admin.Form.AddFieldComponent do 2 | use MishkaHtmlWeb, :live_component 3 | 4 | def render(assigns) do 5 | ~H""" 6 |
7 | 8 | 9 | 10 | 11 | 12 |
13 | برای اضافه کردن فیلد جدید روی اضافه کردن فیلد کلیک کنید 14 |
15 |
16 | """ 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /apps/mishka_html/lib/mishka_html_web/live/components/admin/form/add_tag_component.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaHtmlWeb.Admin.Form.AddTagComponent do 2 | use MishkaHtmlWeb, :live_component 3 | 4 | def render(assigns) do 5 | ~H""" 6 |
7 | <%= label @f , "#{@search_fields.title}:" %> 8 | 9 | <%= text_input @f, String.to_atom(@form.type), class: "form-control bw", phx_keyup: "set_tag", phx_key: "Enter"%> 10 |
11 | <%= error_tag @f, String.to_atom(@form.type) %> 12 |
13 | 14 |
15 | <%= for {tag, color} <- Enum.zip(@tags, Stream.cycle( 16 | ["bg-primary", "bg-secondary", "bg-success", "bg-danger", "bg-warning", "bg-info", "bg-dark"] 17 | )) do %> 18 | 19 | <%= tag %> 20 | 21 | 22 | <% end %> 23 |
24 | """ 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /apps/mishka_html/lib/mishka_html_web/live/components/admin/form/converte_title_to_link_component.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaHtmlWeb.Admin.Form.ConvertTitleToLinkComponent do 2 | use MishkaHtmlWeb, :live_component 3 | 4 | def render(assigns) do 5 | ~H""" 6 |
7 | <%= label @f , "#{@search_fields.title}:" %> 8 | 9 | <%= text_input @f, String.to_atom(@form.type), phx_keyup: "set_link", phx_key: "Enter", class: "form-control bw", value: if !is_nil(@form.value), do: @form.value %> 10 |
11 | <%= error_tag @f, String.to_atom(@form.type) %> 12 |
13 |
14 |
15 | 16 | لینک: 17 | <%= @alias_link %> 18 | 19 |
20 | """ 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /apps/mishka_html/lib/mishka_html_web/live/components/admin/form/editor_component.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaHtmlWeb.Admin.Form.EditorComponent do 2 | use MishkaHtmlWeb, :live_component 3 | 4 | def render(assigns) do 5 | ~H""" 6 |
7 |
8 |
9 |
10 |
11 | <%= error_tag @f, String.to_atom(@form.type) %> 12 |
13 |
14 |
15 | """ 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /apps/mishka_html/lib/mishka_html_web/live/components/admin/form/select_component.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaHtmlWeb.Admin.Form.SelectComponent do 2 | use MishkaHtmlWeb, :live_component 3 | 4 | def render(assigns) do 5 | ~H""" 6 |
7 | <%= label @f , "#{@search_fields.title}:" %> 8 | 9 | <%= select @f, String.to_atom(@form.type), 10 | @search_fields.options, 11 | class: "form-select", 12 | selected: "#{@form.value}" 13 | %> 14 |
15 | <%= error_tag @f, String.to_atom(@form.type) %> 16 |
17 |
18 | """ 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /apps/mishka_html/lib/mishka_html_web/live/components/admin/form/text_component.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaHtmlWeb.Admin.Form.TextComponent do 2 | use MishkaHtmlWeb, :live_component 3 | 4 | def render(assigns) do 5 | ~H""" 6 |
7 | <%= label @f , "#{@search_fields.title}:" %> 8 | 9 | <%= text_input @f, String.to_atom(@form.type), class: "form-control bw", value: if !is_nil(@form.value), do: @form.value %> 10 |
11 | <%= error_tag @f, String.to_atom(@form.type) %> 12 |
13 |
14 | """ 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /apps/mishka_html/lib/mishka_html_web/live/components/admin/form/textarea_component.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaHtmlWeb.Admin.Form.TextAreaComponent do 2 | use MishkaHtmlWeb, :live_component 3 | 4 | def render(assigns) do 5 | ~H""" 6 |
7 | <%= label @f , "#{@search_fields.title}:" %> 8 | 9 | <%= textarea @f, String.to_atom(@form.type), class: "form-control bw", style: "height: 305px", value: if !is_nil(@form.value), do: @form.value %> 10 |
11 | <%= error_tag @f, String.to_atom(@form.type) %> 12 |
13 |
14 | """ 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /apps/mishka_html/lib/mishka_html_web/live/components/admin/public/_live_flash_component.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaHtmlWeb.Admin.Public.LiveFlashComponent do 2 | use MishkaHtmlWeb, :live_component 3 | 4 | def render(assigns) do 5 | ~H""" 6 |
7 | <%= if live_flash(@flash, :info) do %> 8 |
9 | 12 | <% end %> 13 | 14 | <%= if live_flash(@flash, :success) do %> 15 |
16 | 19 | <% end %> 20 | 21 | <%= if live_flash(@flash, :warning) do %> 22 |
23 | 26 | <% end %> 27 | 28 | <%= if live_flash(@flash, :error) do %> 29 |
30 | 33 | <% end %> 34 |
35 | """ 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /apps/mishka_html/lib/mishka_html_web/live/components/admin/public/_modal_component.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaHtmlWeb.Admin.Public.ModalComponent do 2 | use MishkaHtmlWeb, :live_component 3 | 4 | def render(assigns) do 5 | ~H""" 6 |
10 |
11 | <.live_component module={@component} id={:live_modal_status} /> 12 |
13 |
14 | """ 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /apps/mishka_html/lib/mishka_html_web/live/components/admin/public/admin_calendar_component.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaHtmlWeb.Admin.Public.CalendarComponent do 2 | use MishkaHtmlWeb, :live_component 3 | 4 | def render(assigns) do 5 | ~H""" 6 |
7 |
8 |
9 | """ 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /apps/mishka_html/lib/mishka_html_web/live/components/admin/setting/add_field_component.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaHtmlWeb.Admin.Setting.AddFieldComponent do 2 | use MishkaHtmlWeb, :live_component 3 | 4 | def render(assigns) do 5 | ~H""" 6 |
7 |
8 | 9 | 10 | 11 |
12 | 13 |
14 | 15 | 16 |
17 | 18 |
19 |
20 |
21 | """ 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /apps/mishka_html/lib/mishka_html_web/live/components/client/blog_post/sub_comment.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaHtmlWeb.Client.BlogPost.SubComment do 2 | use MishkaHtmlWeb, :live_component 3 | 4 | def render(assigns) do 5 | ~H""" 6 |
10 |
11 | 12 |
13 | 14 | 27 |
28 | 29 |
30 |
31 | """ 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /apps/mishka_html/lib/mishka_html_web/live/components/client/public/_client_header_component.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaHtmlWeb.Client.Public.HeaderComponent do 2 | use MishkaHtmlWeb, :live_component 3 | 4 | def render(assigns) do 5 | ~H""" 6 |
7 |
8 | 9 |
10 |
11 | 12 | <%= live_render(@socket, MishkaHtmlWeb.Client.Public.ClientMenuAndNotif, id: :client_menu_and_notif) %> 13 |
14 | """ 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /apps/mishka_html/lib/mishka_html_web/live/components/client/public/_cright_component.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaHtmlWeb.Client.Public.CrightComponent do 2 | use MishkaHtmlWeb, :live_component 3 | 4 | def render(assigns) do 5 | ~H""" 6 |
7 |
8 |

<%= MishkaTranslator.Gettext.dgettext("html_live_component", "ساخته شده به وسیله ترانگل © 2017–2021") %>

9 |
10 |
11 | """ 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /apps/mishka_html/lib/mishka_html_web/live/components/public/_time_converter_component.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaHtmlWeb.Public.TimeConverterComponent do 2 | use MishkaHtmlWeb, :live_component 3 | 4 | def render(assigns) do 5 | ~H""" 6 | 7 | <% time_need = jalali_create(@time) %> 8 | <%= time_need.day_number %> <%= time_need.month_name %> <%= time_need.year_number %> 9 | 10 | """ 11 | end 12 | 13 | def fix_month_and_day(string_number) do 14 | if String.length("#{string_number}") == 1 do 15 | "0#{string_number}" 16 | else 17 | "#{string_number}" 18 | end 19 | end 20 | 21 | def miladi_to_jalaali(datetime) do 22 | {:ok, jalaali_datetime} = DateTime.convert(datetime, Jalaali.Calendar) 23 | 24 | jalaali_datetime 25 | |> DateTime.to_string() 26 | |> String.replace("Z", "") 27 | end 28 | 29 | def jalali_create(time_need, "number") do 30 | {:ok, jalaali_date} = DateTime.convert(time_need, Jalaali.Calendar) 31 | 32 | %{ 33 | day_number: jalaali_date.day, 34 | month_name: jalaali_date.month, 35 | year_number: jalaali_date.year 36 | } 37 | end 38 | 39 | def jalali_create(time_need) do 40 | {:ok, jalaali_date} = DateTime.convert(time_need, Jalaali.Calendar) 41 | 42 | %{ 43 | day_number: jalaali_date.day, 44 | month_name: get_month(jalaali_date.month), 45 | year_number: jalaali_date.year, 46 | hour: jalaali_date.hour, 47 | minute: jalaali_date.minute, 48 | second: jalaali_date.second 49 | } 50 | end 51 | 52 | def get_month(id) do 53 | case id do 54 | 1 -> "فروردین" 55 | 2 -> "اردیبهشت" 56 | 3 -> "خرداد" 57 | 4 -> "تیر" 58 | 5 -> "مرداد" 59 | 6 -> "شهریور" 60 | 7 -> "مهر" 61 | 8 -> "آبان" 62 | 9 -> "آذر" 63 | 10 -> "دی" 64 | 11 -> "بهمن" 65 | 12 -> "اسفند" 66 | end 67 | end 68 | end 69 | -------------------------------------------------------------------------------- /apps/mishka_html/lib/mishka_html_web/telemetry.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaHtmlWeb.Telemetry do 2 | use Supervisor 3 | import Telemetry.Metrics 4 | 5 | def start_link(arg) do 6 | Supervisor.start_link(__MODULE__, arg, name: __MODULE__) 7 | end 8 | 9 | @impl true 10 | def init(_arg) do 11 | children = [ 12 | # Telemetry poller will execute the given period measurements 13 | # every 10_000ms. Learn more here: https://hexdocs.pm/telemetry_metrics 14 | {:telemetry_poller, measurements: periodic_measurements(), period: 10_000} 15 | # Add reporters as children of your supervision tree. 16 | # {Telemetry.Metrics.ConsoleReporter, metrics: metrics()} 17 | ] 18 | 19 | Supervisor.init(children, strategy: :one_for_one) 20 | end 21 | 22 | def metrics do 23 | [ 24 | # Phoenix Metrics 25 | summary("phoenix.endpoint.stop.duration", 26 | unit: {:native, :millisecond} 27 | ), 28 | summary("phoenix.router_dispatch.stop.duration", 29 | tags: [:route], 30 | unit: {:native, :millisecond} 31 | ), 32 | 33 | # VM Metrics 34 | summary("vm.memory.total", unit: {:byte, :kilobyte}), 35 | summary("vm.total_run_queue_lengths.total"), 36 | summary("vm.total_run_queue_lengths.cpu"), 37 | summary("vm.total_run_queue_lengths.io") 38 | ] 39 | end 40 | 41 | defp periodic_measurements do 42 | [ 43 | # A module, function and arguments to be invoked periodically. 44 | # This function must call :telemetry.execute/3 and a metric must be added above. 45 | # {MishkaHtmlWeb, :count_users, []} 46 | ] 47 | end 48 | end 49 | -------------------------------------------------------------------------------- /apps/mishka_html/lib/mishka_html_web/templates/admin_dashboard/admin_dashboard_live.html.heex: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | <%= live_render(@socket, MishkaHtmlWeb.Admin.Public.AdminMenu, id: :admin_menu) %> 5 | <.live_component module={MishkaHtmlWeb.Admin.Dashboard.QuickmenuMenuComponent} 6 | id={:admin_quickmenu} 7 | activities={@activities} 8 | /> 9 | 10 |
11 |
12 | <.live_component module={MishkaHtmlWeb.Admin.Dashboard.LastUsersComponent} id={:admin_last_users} users={@users} /> 13 | <.live_component module={MishkaHtmlWeb.Admin.Dashboard.LastNotifComponent} id={:admin_notif} notifs={@notifs} /> 14 |
15 |
16 |
17 | 18 | 19 |
20 | 21 | 22 | 23 | <.live_component module={MishkaHtmlWeb.Admin.Public.CalendarComponent} id={:admin_calendar} /> 24 | 25 | 26 |
27 | <.live_component module={MishkaHtmlWeb.Admin.Dashboard.LastBlogPostsComponent} id={:admin_last_blog_posts} posts={@posts} /> 28 |
29 | 30 |
31 |
32 |
33 | -------------------------------------------------------------------------------- /apps/mishka_html/lib/mishka_html_web/templates/admin_media_manager/admin_media_manager_live.html.heex: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahryarjb/mishka-cms/45563d985f98217f57e25829375835d93f540a6e/apps/mishka_html/lib/mishka_html_web/templates/admin_media_manager/admin_media_manager_live.html.heex -------------------------------------------------------------------------------- /apps/mishka_html/lib/mishka_html_web/templates/admin_seo/admin_seo_live.html.heex: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahryarjb/mishka-cms/45563d985f98217f57e25829375835d93f540a6e/apps/mishka_html/lib/mishka_html_web/templates/admin_seo/admin_seo_live.html.heex -------------------------------------------------------------------------------- /apps/mishka_html/lib/mishka_html_web/templates/client_auth/login_live.html.heex: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | <.live_component module={MishkaHtmlWeb.Client.Public.HeaderComponent} id={:client_header} /> 5 | 6 |
7 | <.live_component module={MishkaHtmlWeb.Admin.Public.LiveFlashComponent} id={:live_flash} flash={@flash} /> 8 |
9 | <.live_component module={MishkaHtmlWeb.Client.Login.LoginFormComponent} id={:login_form} changeset={@changeset} trigger_submit={@trigger_submit} /> 10 | 11 |
12 | <%= 13 | state = %MishkaInstaller.Reference.OnUserBeforeLogin{ip: @user_ip, assigns: assigns, output: nil, input: @input} 14 | MishkaInstaller.Hook.call(event: "on_user_before_login", state: state).output 15 | %> 16 |
17 | 18 |
19 |
20 |
21 | <.live_component module={MishkaHtmlWeb.Client.Public.CrightComponent} id={:cright} /> 22 | -------------------------------------------------------------------------------- /apps/mishka_html/lib/mishka_html_web/templates/client_auth/register_live.html.heex: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | <.live_component module={MishkaHtmlWeb.Client.Public.HeaderComponent} id={:client_header} /> 5 | 6 |
7 | <.live_component module={MishkaHtmlWeb.Admin.Public.LiveFlashComponent} id={:live_flash} flash={@flash} /> 8 |
9 | <.live_component module={MishkaHtmlWeb.Client.Register.RegisterFormComponent} id={:login_form} changeset={@changeset} /> 10 |
11 |
12 |
13 | <.live_component module={MishkaHtmlWeb.Client.Public.CrightComponent} id={:cright} /> 14 | -------------------------------------------------------------------------------- /apps/mishka_html/lib/mishka_html_web/templates/layout/app.html.heex: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | <%= @inner_content %> 5 |
6 | -------------------------------------------------------------------------------- /apps/mishka_html/lib/mishka_html_web/templates/layout/live.html.heex: -------------------------------------------------------------------------------- 1 | 6 |
7 | <%= @inner_content %> 8 |
9 | -------------------------------------------------------------------------------- /apps/mishka_html/lib/mishka_html_web/templates/layout/root.html.heex: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | <%= csrf_meta_tag() %> 8 | <%= live_title_tag assigns[:page_title] || "MishkaCMS"%> 9 | <%= seo_tags(assigns[:seo_tags]) %> 10 | 11 | 12 | 13 | 14 | 15 | 16 | <%= if MishkaInstaller.Helper.Setting.get("google_captcha")["status"] == "production" do %> 17 | <%= if !is_nil(client = MishkaInstaller.Helper.Setting.get("google_captcha")["client"]) do %> 18 | 19 | <% end %> 20 | <% end %> 21 | 22 | 23 | <%= @inner_content %> 24 | 25 | 26 | -------------------------------------------------------------------------------- /apps/mishka_html/lib/mishka_html_web/views/admin_activity_view.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaHtmlWeb.AdminActivityView do 2 | use MishkaHtmlWeb, :view 3 | end 4 | -------------------------------------------------------------------------------- /apps/mishka_html/lib/mishka_html_web/views/admin_blog_view.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaHtmlWeb.AdminBlogView do 2 | use MishkaHtmlWeb, :view 3 | end 4 | -------------------------------------------------------------------------------- /apps/mishka_html/lib/mishka_html_web/views/admin_comment_view.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaHtmlWeb.AdminCommentView do 2 | use MishkaHtmlWeb, :view 3 | end 4 | -------------------------------------------------------------------------------- /apps/mishka_html/lib/mishka_html_web/views/admin_dashboard_view.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaHtmlWeb.AdminDashboardView do 2 | use MishkaHtmlWeb, :view 3 | end 4 | -------------------------------------------------------------------------------- /apps/mishka_html/lib/mishka_html_web/views/admin_media_manager_view.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaHtmlWeb.AdminMediaManagerView do 2 | use MishkaHtmlWeb, :view 3 | end 4 | -------------------------------------------------------------------------------- /apps/mishka_html/lib/mishka_html_web/views/admin_notif_view.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaHtmlWeb.AdminNotifView do 2 | use MishkaHtmlWeb, :view 3 | end 4 | -------------------------------------------------------------------------------- /apps/mishka_html/lib/mishka_html_web/views/admin_seo_view.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaHtmlWeb.AdminSeoView do 2 | use MishkaHtmlWeb, :view 3 | end 4 | -------------------------------------------------------------------------------- /apps/mishka_html/lib/mishka_html_web/views/admin_setting_view.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaHtmlWeb.AdminSettingView do 2 | use MishkaHtmlWeb, :view 3 | end 4 | -------------------------------------------------------------------------------- /apps/mishka_html/lib/mishka_html_web/views/admin_subscription_view.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaHtmlWeb.AdminSubscriptionView do 2 | use MishkaHtmlWeb, :view 3 | end 4 | -------------------------------------------------------------------------------- /apps/mishka_html/lib/mishka_html_web/views/admin_user_view.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaHtmlWeb.AdminUserView do 2 | use MishkaHtmlWeb, :view 3 | end 4 | -------------------------------------------------------------------------------- /apps/mishka_html/lib/mishka_html_web/views/client_auth_view.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaHtmlWeb.ClientAuthView do 2 | use MishkaHtmlWeb, :view 3 | end 4 | -------------------------------------------------------------------------------- /apps/mishka_html/lib/mishka_html_web/views/client_blog_view.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaHtmlWeb.ClientBlogView do 2 | use MishkaHtmlWeb, :view 3 | end 4 | -------------------------------------------------------------------------------- /apps/mishka_html/lib/mishka_html_web/views/client_home_view.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaHtmlWeb.ClientHomeView do 2 | use MishkaHtmlWeb, :view 3 | end 4 | -------------------------------------------------------------------------------- /apps/mishka_html/lib/mishka_html_web/views/client_notif_view.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaHtmlWeb.ClientNotifView do 2 | use MishkaHtmlWeb, :view 3 | end 4 | -------------------------------------------------------------------------------- /apps/mishka_html/lib/mishka_html_web/views/error_helpers.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaHtmlWeb.ErrorHelpers do 2 | @moduledoc """ 3 | Conveniences for translating and building error messages. 4 | """ 5 | 6 | use Phoenix.HTML 7 | 8 | @doc """ 9 | Generates tag for inlined form input errors. 10 | """ 11 | def error_tag(form, field) do 12 | Enum.map(Keyword.get_values(form.errors, field), fn error -> 13 | content_tag(:span, translate_error(error), 14 | class: "invalid-feedback", 15 | phx_feedback_for: input_name(form, field) 16 | ) 17 | end) 18 | end 19 | 20 | @doc """ 21 | Translates an error message using gettext. 22 | """ 23 | def translate_error({msg, opts}) do 24 | # When using gettext, we typically pass the strings we want 25 | # to translate as a static argument: 26 | # 27 | # # Translate "is invalid" in the "errors" domain 28 | # dgettext("errors", "is invalid") 29 | # 30 | # # Translate the number of files with plural rules 31 | # dngettext("errors", "1 file", "%{count} files", count) 32 | # 33 | # Because the error messages we show in our forms and APIs 34 | # are defined inside Ecto, we need to translate them dynamically. 35 | # This requires us to call the Gettext module passing our gettext 36 | # backend as first argument. 37 | # 38 | # Note we use the "errors" domain, which means translations 39 | # should be written to the errors.po file. The :count option is 40 | # set by Ecto and indicates we should also apply plural rules. 41 | if count = opts[:count] do 42 | Gettext.dngettext(MishkaHtmlWeb.Gettext, "errors", msg, msg, count, opts) 43 | else 44 | Gettext.dgettext(MishkaHtmlWeb.Gettext, "errors", msg, opts) 45 | end 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /apps/mishka_html/lib/mishka_html_web/views/error_view.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaHtmlWeb.ErrorView do 2 | use MishkaHtmlWeb, :view 3 | 4 | # If you want to customize a particular status code 5 | # for a certain format, you may uncomment below. 6 | # def render("500.html", _assigns) do 7 | # "Internal Server Error" 8 | # end 9 | 10 | # By default, Phoenix returns the status message from 11 | # the template name. For example, "404.html" becomes 12 | # "Not Found". 13 | def template_not_found(template, _assigns) do 14 | Phoenix.Controller.status_message_from_template(template) 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /apps/mishka_html/priv/static/css/font.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'Iconly-bulk'; 3 | src: url('../fonts/Iconly-bulk.eot?7ldoi4'); 4 | src: url('../fonts/Iconly-bulk.eot?7ldoi4#iefix') format('embedded-opentype'), 5 | url('../fonts/Iconly-bulk.ttf?7ldoi4') format('truetype'), 6 | url('../fonts/Iconly-bulk.woff?7ldoi4') format('woff'), 7 | url('../fonts/Iconly-bulk.svg?7ldoi4#Iconly-bulk') format('svg'); 8 | font-weight: normal; 9 | font-style: normal; 10 | font-display: block; 11 | } 12 | 13 | @font-face { 14 | font-family: 'Vazir-Regular'; 15 | src: url('../fonts/Vazir-Regular.eot?7ldoi4'); 16 | src: url('../fonts/Vazir-Regular.eot?7ldoi4#iefix') format('embedded-opentype'), 17 | url('../fonts/Vazir-Regular.ttf?7ldoi4') format('truetype'), 18 | url('../fonts/Vazir-Regular.woff?7ldoi4') format('woff'); 19 | 20 | 21 | font-weight: normal; 22 | font-style: normal; 23 | font-display: block; 24 | } -------------------------------------------------------------------------------- /apps/mishka_html/priv/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahryarjb/mishka-cms/45563d985f98217f57e25829375835d93f540a6e/apps/mishka_html/priv/static/favicon.ico -------------------------------------------------------------------------------- /apps/mishka_html/priv/static/fonts/Iconly-bulk.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahryarjb/mishka-cms/45563d985f98217f57e25829375835d93f540a6e/apps/mishka_html/priv/static/fonts/Iconly-bulk.eot -------------------------------------------------------------------------------- /apps/mishka_html/priv/static/fonts/Iconly-bulk.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahryarjb/mishka-cms/45563d985f98217f57e25829375835d93f540a6e/apps/mishka_html/priv/static/fonts/Iconly-bulk.ttf -------------------------------------------------------------------------------- /apps/mishka_html/priv/static/fonts/Iconly-bulk.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahryarjb/mishka-cms/45563d985f98217f57e25829375835d93f540a6e/apps/mishka_html/priv/static/fonts/Iconly-bulk.woff -------------------------------------------------------------------------------- /apps/mishka_html/priv/static/fonts/Iconly-light.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahryarjb/mishka-cms/45563d985f98217f57e25829375835d93f540a6e/apps/mishka_html/priv/static/fonts/Iconly-light.eot -------------------------------------------------------------------------------- /apps/mishka_html/priv/static/fonts/Vazir-Regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahryarjb/mishka-cms/45563d985f98217f57e25829375835d93f540a6e/apps/mishka_html/priv/static/fonts/Vazir-Regular.eot -------------------------------------------------------------------------------- /apps/mishka_html/priv/static/fonts/Vazir-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahryarjb/mishka-cms/45563d985f98217f57e25829375835d93f540a6e/apps/mishka_html/priv/static/fonts/Vazir-Regular.ttf -------------------------------------------------------------------------------- /apps/mishka_html/priv/static/fonts/Vazir-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahryarjb/mishka-cms/45563d985f98217f57e25829375835d93f540a6e/apps/mishka_html/priv/static/fonts/Vazir-Regular.woff -------------------------------------------------------------------------------- /apps/mishka_html/priv/static/fonts/Vazir-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahryarjb/mishka-cms/45563d985f98217f57e25829375835d93f540a6e/apps/mishka_html/priv/static/fonts/Vazir-Regular.woff2 -------------------------------------------------------------------------------- /apps/mishka_html/priv/static/fonts/bootstrap-icons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahryarjb/mishka-cms/45563d985f98217f57e25829375835d93f540a6e/apps/mishka_html/priv/static/fonts/bootstrap-icons.woff -------------------------------------------------------------------------------- /apps/mishka_html/priv/static/fonts/bootstrap-icons.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahryarjb/mishka-cms/45563d985f98217f57e25829375835d93f540a6e/apps/mishka_html/priv/static/fonts/bootstrap-icons.woff2 -------------------------------------------------------------------------------- /apps/mishka_html/priv/static/fonts/font.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'Iconly-bulk'; 3 | src: url('./fonts/Iconly-bulk.eot?7ldoi4'); 4 | src: url('./fonts/Iconly-bulk.eot?7ldoi4#iefix') format('embedded-opentype'), 5 | url('./fonts/Iconly-bulk.ttf?7ldoi4') format('truetype'), 6 | url('./fonts/Iconly-bulk.woff?7ldoi4') format('woff'), 7 | url('./fonts/Iconly-bulk.svg?7ldoi4#Iconly-bulk') format('svg'); 8 | font-weight: normal; 9 | font-style: normal; 10 | font-display: block; 11 | } 12 | 13 | @font-face { 14 | font-family: 'Vazir-Regular'; 15 | src: url('../fonts/Vazir-Regular.eot?7ldoi4'); 16 | src: url('../fonts/Vazir-Regular.eot?7ldoi4#iefix') format('embedded-opentype'), 17 | url('../fonts/Vazir-Regular.ttf?7ldoi4') format('truetype'), 18 | url('../fonts/Vazir-Regular.woff?7ldoi4') format('woff'); 19 | 20 | 21 | font-weight: normal; 22 | font-style: normal; 23 | font-display: block; 24 | } -------------------------------------------------------------------------------- /apps/mishka_html/priv/static/images/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahryarjb/mishka-cms/45563d985f98217f57e25829375835d93f540a6e/apps/mishka_html/priv/static/images/1.jpg -------------------------------------------------------------------------------- /apps/mishka_html/priv/static/images/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahryarjb/mishka-cms/45563d985f98217f57e25829375835d93f540a6e/apps/mishka_html/priv/static/images/2.jpg -------------------------------------------------------------------------------- /apps/mishka_html/priv/static/images/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahryarjb/mishka-cms/45563d985f98217f57e25829375835d93f540a6e/apps/mishka_html/priv/static/images/3.jpg -------------------------------------------------------------------------------- /apps/mishka_html/priv/static/images/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahryarjb/mishka-cms/45563d985f98217f57e25829375835d93f540a6e/apps/mishka_html/priv/static/images/4.jpg -------------------------------------------------------------------------------- /apps/mishka_html/priv/static/images/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahryarjb/mishka-cms/45563d985f98217f57e25829375835d93f540a6e/apps/mishka_html/priv/static/images/5.jpg -------------------------------------------------------------------------------- /apps/mishka_html/priv/static/images/icons8-login-as-user-80.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahryarjb/mishka-cms/45563d985f98217f57e25829375835d93f540a6e/apps/mishka_html/priv/static/images/icons8-login-as-user-80.png -------------------------------------------------------------------------------- /apps/mishka_html/priv/static/images/mylogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahryarjb/mishka-cms/45563d985f98217f57e25829375835d93f540a6e/apps/mishka_html/priv/static/images/mylogo.png -------------------------------------------------------------------------------- /apps/mishka_html/priv/static/images/no-user-image.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahryarjb/mishka-cms/45563d985f98217f57e25829375835d93f540a6e/apps/mishka_html/priv/static/images/no-user-image.jpg -------------------------------------------------------------------------------- /apps/mishka_html/priv/static/js/check_editor_extended.js: -------------------------------------------------------------------------------- 1 | const classCheckEditor = require('./ckeditor'); 2 | 3 | classCheckEditor.A.prototype.cleanup = function() { 4 | 5 | } 6 | 7 | module.exports = classCheckEditor; -------------------------------------------------------------------------------- /apps/mishka_html/priv/static/js/translations/af.js: -------------------------------------------------------------------------------- 1 | (function(e){const n=e["af"]=e["af"]||{};n.dictionary=Object.assign(n.dictionary||{},{"Align center":"Belyn in die middel","Align left":"Belyn links","Align right":"Belyn regs","Block quote":"Blok-aanhaling",Bold:"Vetgedruk",Cancel:"Kanselleer",Code:"Kode",Italic:"Skuinsgedruk",Justify:"Belyn beide kante","Remove color":"","Remove Format":"Verwyder formatering","Restore default":"",Save:"Berg","Show more items":"",Strikethrough:"Deurgetrek","Text alignment":"Teksbelyning","Text alignment toolbar":"",Underline:"Onderstreep"});n.getPluralForm=function(e){return e!=1}})(window.CKEDITOR_TRANSLATIONS||(window.CKEDITOR_TRANSLATIONS={})); -------------------------------------------------------------------------------- /apps/mishka_html/priv/static/js/translations/ca.js: -------------------------------------------------------------------------------- 1 | (function(a){const e=a["ca"]=a["ca"]||{};e.dictionary=Object.assign(e.dictionary||{},{"Align center":"Alineació centre","Align left":"Alineació esquerra","Align right":"Alineació dreta",Big:"Gran","Block quote":"Cita de bloc","Blue marker":"Marcador blau",Bold:"Negreta",Cancel:"Cancel·lar","Choose heading":"Escull capçalera",Code:"Codi",Default:"Predeterminada","Document colors":"","Font Background Color":"","Font Color":"","Font Size":"Mida de la font","Green marker":"Marcador verd","Green pen":"Bolígraf verd",Heading:"Capçalera","Heading 1":"Capçalera 1","Heading 2":"Capçalera 2","Heading 3":"Capçalera 3","Heading 4":"","Heading 5":"","Heading 6":"",Highlight:"Destacat",Huge:"Molt gran",Italic:"Cursiva",Justify:"Justificar",Paragraph:"Pàrraf","Pink marker":"Marcador rosa","Red pen":"Marcador vermell","Remove color":"","Remove highlight":"Esborrar destacat","Restore default":"",Save:"Desar","Show more items":"",Small:"Peita",Strikethrough:"Marcat","Text alignment":"Alineació text","Text alignment toolbar":"","Text highlight toolbar":"",Tiny:"Molt petita",Underline:"Subrallat","Yellow marker":"Marcador groc"});e.getPluralForm=function(a){return a!=1}})(window.CKEDITOR_TRANSLATIONS||(window.CKEDITOR_TRANSLATIONS={})); -------------------------------------------------------------------------------- /apps/mishka_html/priv/static/js/translations/gu.js: -------------------------------------------------------------------------------- 1 | (function(n){const o=n["gu"]=n["gu"]||{};o.dictionary=Object.assign(o.dictionary||{},{"Block quote":" વિચાર ટાંકો",Bold:"ઘાટુ - બોલ્ડ્",Code:"",Italic:"ત્રાંસુ - ઇટલિક્",Strikethrough:"",Underline:"નીચે લિટી - અન્ડરલાઇન્"});o.getPluralForm=function(n){return n!=1}})(window.CKEDITOR_TRANSLATIONS||(window.CKEDITOR_TRANSLATIONS={})); -------------------------------------------------------------------------------- /apps/mishka_html/priv/static/js/translations/kk.js: -------------------------------------------------------------------------------- 1 | (function(n){const t=n["kk"]=n["kk"]||{};t.dictionary=Object.assign(t.dictionary||{},{"Align center":"Ортадан туралау","Align left":"Солға туралау","Align right":"Оңға туралау",Justify:"","Text alignment":"Мәтінді туралау","Text alignment toolbar":"Мәтінді туралау құралдар тақтасы"});t.getPluralForm=function(n){return n!=1}})(window.CKEDITOR_TRANSLATIONS||(window.CKEDITOR_TRANSLATIONS={})); -------------------------------------------------------------------------------- /apps/mishka_html/priv/static/js/translations/oc.js: -------------------------------------------------------------------------------- 1 | (function(o){const e=o["oc"]=o["oc"]||{};e.dictionary=Object.assign(e.dictionary||{},{Bold:"Gras",Cancel:"Anullar",Code:"",Italic:"Italica","Remove color":"","Restore default":"",Save:"Enregistrar","Show more items":"",Strikethrough:"",Underline:""});e.getPluralForm=function(o){return o>1}})(window.CKEDITOR_TRANSLATIONS||(window.CKEDITOR_TRANSLATIONS={})); -------------------------------------------------------------------------------- /apps/mishka_html/priv/static/js/translations/si.js: -------------------------------------------------------------------------------- 1 | (function(e){const t=e["si"]=e["si"]||{};t.dictionary=Object.assign(t.dictionary||{},{Bold:"තදකුරු","Break text":"","Bulleted List":"බුලටිත ලැයිස්තුව","Bulleted list styles toolbar":"","Centered image":"","Change image text alternative":"",Circle:"",Code:"",Decimal:"","Decimal with leading zero":"",Disc:"","Enter image caption":"","Full size image":"","Image resize list":"","Image toolbar":"","image widget":"","In line":"",Insert:"","Insert image":"පින්තූරය ඇතුල් කරන්න","Insert image via URL":"",Italic:"ඇලකුරු","Left aligned image":"","Lower-latin":"","Lower–roman":"","Numbered List":"අංකිත ලැයිස්තුව","Numbered list styles toolbar":"",Original:"",Redo:"නැවත කරන්න","Resize image":"","Resize image to %0":"","Resize image to the original size":"","Right aligned image":"","Side image":"",Square:"",Strikethrough:"","Text alternative":"","To-do List":"","Toggle the circle list style":"","Toggle the decimal list style":"","Toggle the decimal with leading zero list style":"","Toggle the disc list style":"","Toggle the lower–latin list style":"","Toggle the lower–roman list style":"","Toggle the square list style":"","Toggle the upper–latin list style":"","Toggle the upper–roman list style":"",Underline:"",Undo:"අහෝසි කරන්න",Update:"","Update image URL":"","Upload failed":"උඩුගත කිරීම අසාර්ථක විය","Upper-latin":"","Upper-roman":"","Wrap text":""});t.getPluralForm=function(e){return e!=1}})(window.CKEDITOR_TRANSLATIONS||(window.CKEDITOR_TRANSLATIONS={})); -------------------------------------------------------------------------------- /apps/mishka_html/priv/static/js/translations/tt.js: -------------------------------------------------------------------------------- 1 | (function(o){const t=o["tt"]=o["tt"]||{};t.dictionary=Object.assign(t.dictionary||{},{Bold:"Калын",Cancel:"",Code:"Код",Italic:"",Redo:"Кабатла","Remove color":"","Restore default":"",Save:"Сакла","Show more items":"",Strikethrough:"",Underline:"",Undo:""});t.getPluralForm=function(o){return 0}})(window.CKEDITOR_TRANSLATIONS||(window.CKEDITOR_TRANSLATIONS={})); -------------------------------------------------------------------------------- /apps/mishka_html/priv/static/robots.txt: -------------------------------------------------------------------------------- 1 | # See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file 2 | # 3 | # To ban all spiders from the entire site uncomment the next two lines: 4 | # User-agent: * 5 | # Disallow: / 6 | -------------------------------------------------------------------------------- /apps/mishka_html/test/mishka_html_web/live/page_live_test.exs: -------------------------------------------------------------------------------- 1 | defmodule MishkaHtmlWeb.PageLiveTest do 2 | use MishkaHtmlWeb.ConnCase 3 | 4 | # import Phoenix.LiveViewTest 5 | 6 | # test "disconnected and connected render", %{conn: conn} do 7 | # {:ok, page_live, disconnected_html} = live(conn, "/") 8 | # assert disconnected_html =~ "Welcome to Phoenix!" 9 | # assert render(page_live) =~ "Welcome to Phoenix!" 10 | # end 11 | end 12 | -------------------------------------------------------------------------------- /apps/mishka_html/test/mishka_html_web/views/error_view_test.exs: -------------------------------------------------------------------------------- 1 | defmodule MishkaHtmlWeb.ErrorViewTest do 2 | use MishkaHtmlWeb.ConnCase, async: true 3 | 4 | # Bring render/3 and render_to_string/3 for testing custom views 5 | import Phoenix.View 6 | 7 | test "renders 404.html" do 8 | assert render_to_string(MishkaHtmlWeb.ErrorView, "404.html", []) == "Not Found" 9 | end 10 | 11 | test "renders 500.html" do 12 | assert render_to_string(MishkaHtmlWeb.ErrorView, "500.html", []) == "Internal Server Error" 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /apps/mishka_html/test/mishka_html_web/views/layout_view_test.exs: -------------------------------------------------------------------------------- 1 | defmodule MishkaHtmlWeb.LayoutViewTest do 2 | use MishkaHtmlWeb.ConnCase, async: true 3 | 4 | # When testing helpers, you may want to import Phoenix.HTML and 5 | # use functions such as safe_to_string() to convert the helper 6 | # result into an HTML string. 7 | # import Phoenix.HTML 8 | end 9 | -------------------------------------------------------------------------------- /apps/mishka_html/test/support/channel_case.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaHtmlWeb.ChannelCase do 2 | @moduledoc """ 3 | This module defines the test case to be used by 4 | channel tests. 5 | 6 | Such tests rely on `Phoenix.ChannelTest` and also 7 | import other functionality to make it easier 8 | to build common data structures and query the data layer. 9 | 10 | Finally, if the test case interacts with the database, 11 | we enable the SQL sandbox, so changes done to the database 12 | are reverted at the end of every test. If you are using 13 | PostgreSQL, you can even run database tests asynchronously 14 | by setting `use MishkaHtmlWeb.ChannelCase, async: true`, although 15 | this option is not recommended for other databases. 16 | """ 17 | 18 | use ExUnit.CaseTemplate 19 | 20 | using do 21 | quote do 22 | # Import conveniences for testing with channels 23 | import Phoenix.ChannelTest 24 | import MishkaHtmlWeb.ChannelCase 25 | 26 | # The default endpoint for testing 27 | @endpoint MishkaHtmlWeb.Endpoint 28 | end 29 | end 30 | 31 | setup _tags do 32 | :ok 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /apps/mishka_html/test/support/conn_case.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaHtmlWeb.ConnCase do 2 | @moduledoc """ 3 | This module defines the test case to be used by 4 | tests that require setting up a connection. 5 | 6 | Such tests rely on `Phoenix.ConnTest` and also 7 | import other functionality to make it easier 8 | to build common data structures and query the data layer. 9 | 10 | Finally, if the test case interacts with the database, 11 | we enable the SQL sandbox, so changes done to the database 12 | are reverted at the end of every test. If you are using 13 | PostgreSQL, you can even run database tests asynchronously 14 | by setting `use MishkaHtmlWeb.ConnCase, async: true`, although 15 | this option is not recommended for other databases. 16 | """ 17 | 18 | use ExUnit.CaseTemplate 19 | 20 | using do 21 | quote do 22 | # Import conveniences for testing with connections 23 | import Plug.Conn 24 | import Phoenix.ConnTest 25 | import MishkaHtmlWeb.ConnCase 26 | 27 | alias MishkaHtmlWeb.Router.Helpers, as: Routes 28 | 29 | # The default endpoint for testing 30 | @endpoint MishkaHtmlWeb.Endpoint 31 | end 32 | end 33 | 34 | setup _tags do 35 | {:ok, conn: Phoenix.ConnTest.build_conn()} 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /apps/mishka_html/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /apps/mishka_translator/.formatter.exs: -------------------------------------------------------------------------------- 1 | # Used by "mix format" 2 | [ 3 | inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] 4 | ] 5 | -------------------------------------------------------------------------------- /apps/mishka_translator/.gitignore: -------------------------------------------------------------------------------- 1 | # The directory Mix will write compiled artifacts to. 2 | /_build/ 3 | 4 | # If you run "mix test --cover", coverage assets end up here. 5 | /cover/ 6 | 7 | # The directory Mix downloads your dependencies sources to. 8 | /deps/ 9 | 10 | # Where third-party dependencies like ExDoc output generated docs. 11 | /doc/ 12 | 13 | # Ignore .fetch files in case you like to edit your project deps locally. 14 | /.fetch 15 | 16 | # If the VM crashes, it generates a dump, let's ignore it too. 17 | erl_crash.dump 18 | 19 | # Also ignore archive artifacts (built via "mix archive.build"). 20 | *.ez 21 | 22 | # Ignore package tarball (built via "mix hex.build"). 23 | mishka_translator-*.tar 24 | 25 | # Temporary files, for example, from tests. 26 | /tmp/ 27 | -------------------------------------------------------------------------------- /apps/mishka_translator/README.md: -------------------------------------------------------------------------------- 1 | # MishkaTranslator 2 | 3 | **TODO: Add description** 4 | 5 | ## Installation 6 | 7 | If [available in Hex](https://hex.pm/docs/publish), the package can be installed 8 | by adding `mishka_translator` to your list of dependencies in `mix.exs`: 9 | 10 | ```elixir 11 | def deps do 12 | [ 13 | {:mishka_translator, "~> 0.1.0"} 14 | ] 15 | end 16 | ``` 17 | 18 | Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc) 19 | and published on [HexDocs](https://hexdocs.pm). Once published, the docs can 20 | be found at [https://hexdocs.pm/mishka_translator](https://hexdocs.pm/mishka_translator). 21 | 22 | -------------------------------------------------------------------------------- /apps/mishka_translator/lib/gettext.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaTranslator.Gettext do 2 | use Gettext, otp_app: :mishka_translator 3 | end 4 | -------------------------------------------------------------------------------- /apps/mishka_translator/lib/mishka_translator.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaTranslator do 2 | end 3 | -------------------------------------------------------------------------------- /apps/mishka_translator/lib/mishka_translator/application.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaTranslator.Application do 2 | # See https://hexdocs.pm/elixir/Application.html 3 | # for more information on OTP Applications 4 | @moduledoc false 5 | 6 | use Application 7 | 8 | @impl true 9 | def start(_type, _args) do 10 | children = [ 11 | # Starts a worker by calling: MishkaTranslator.Worker.start_link(arg) 12 | # {MishkaTranslator.Worker, arg} 13 | ] 14 | 15 | # See https://hexdocs.pm/elixir/Supervisor.html 16 | # for other strategies and supported options 17 | opts = [strategy: :one_for_one, name: MishkaTranslator.Supervisor] 18 | Supervisor.start_link(children, opts) 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /apps/mishka_translator/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule MishkaTranslator.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :mishka_translator, 7 | version: "0.0.2", 8 | build_path: "../../_build", 9 | config_path: "../../config/config.exs", 10 | deps_path: "../../deps", 11 | lockfile: "../../mix.lock", 12 | elixir: "~> 1.13", 13 | compilers: [:gettext] ++ Mix.compilers(), 14 | start_permanent: Mix.env() == :prod, 15 | deps: deps() 16 | ] 17 | end 18 | 19 | # Run "mix help compile.app" to learn about applications. 20 | def application do 21 | [ 22 | extra_applications: [:logger], 23 | mod: {MishkaTranslator.Application, []} 24 | ] 25 | end 26 | 27 | # Run "mix help deps" to learn about dependencies. 28 | defp deps do 29 | [ 30 | {:gettext, "~> 0.19.1"} 31 | ] 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /apps/mishka_translator/priv/gettext/db_schema_public.pot: -------------------------------------------------------------------------------- 1 | ## This file is a PO Template file. 2 | ## 3 | ## "msgid"s here are often extracted from source code. 4 | ## Add new translations manually only if they're dynamic 5 | ## translations that can't be statically extracted. 6 | ## 7 | ## Run "mix gettext.extract" to bring this file up to 8 | ## date. Leave "msgstr"s empty as changing them here as no 9 | ## effect: edit them in PO (.po) files instead. 10 | msgid "" 11 | msgstr "" 12 | 13 | #, elixir-format 14 | #: lib/schema/public/setting.ex:22 15 | msgid "برای این بخش قبلا تنظیمات وارد شده است." 16 | msgstr "" 17 | 18 | #, elixir-format 19 | #: lib/schema/public/setting.ex:21 20 | msgid "فیلد مذکور نمی تواند خالی باشد" 21 | msgstr "" 22 | -------------------------------------------------------------------------------- /apps/mishka_translator/priv/gettext/default.pot: -------------------------------------------------------------------------------- 1 | ## This file is a PO Template file. 2 | ## 3 | ## "msgid"s here are often extracted from source code. 4 | ## Add new translations manually only if they're dynamic 5 | ## translations that can't be statically extracted. 6 | ## 7 | ## Run "mix gettext.extract" to bring this file up to 8 | ## date. Leave "msgstr"s empty as changing them here as no 9 | ## effect: edit them in PO (.po) files instead. 10 | msgid "" 11 | msgstr "" 12 | 13 | #, elixir-format 14 | #: lib/mishka_html.ex:63 15 | msgid "Here is one string to html render" 16 | msgstr "" 17 | -------------------------------------------------------------------------------- /apps/mishka_translator/priv/gettext/en/LC_MESSAGES/db_schema_public.po: -------------------------------------------------------------------------------- 1 | ## "msgid"s in this file come from POT (.pot) files. 2 | ## 3 | ## Do not add, change, or remove "msgid"s manually here as 4 | ## they're tied to the ones in the corresponding POT file 5 | ## (with the same domain). 6 | ## 7 | ## Use "mix gettext.extract --merge" or "mix gettext.merge" 8 | ## to merge POT files into PO files. 9 | msgid "" 10 | msgstr "" 11 | "Language: en\n" 12 | "Plural-Forms: nplurals=2\n" 13 | 14 | #, elixir-format 15 | #: lib/schema/public/setting.ex:22 16 | msgid "برای این بخش قبلا تنظیمات وارد شده است." 17 | msgstr "" 18 | 19 | #, elixir-format 20 | #: lib/schema/public/setting.ex:21 21 | msgid "فیلد مذکور نمی تواند خالی باشد" 22 | msgstr "" 23 | -------------------------------------------------------------------------------- /apps/mishka_translator/priv/gettext/en/LC_MESSAGES/default.po: -------------------------------------------------------------------------------- 1 | ## "msgid"s in this file come from POT (.pot) files. 2 | ## 3 | ## Do not add, change, or remove "msgid"s manually here as 4 | ## they're tied to the ones in the corresponding POT file 5 | ## (with the same domain). 6 | ## 7 | ## Use "mix gettext.extract --merge" or "mix gettext.merge" 8 | ## to merge POT files into PO files. 9 | msgid "" 10 | msgstr "" 11 | "Language: en\n" 12 | "Plural-Forms: nplurals=2\n" 13 | 14 | #, elixir-format 15 | #: lib/mishka_html.ex:63 16 | msgid "Here is one string to html render" 17 | msgstr "" 18 | -------------------------------------------------------------------------------- /apps/mishka_translator/priv/gettext/en/LC_MESSAGES/errors.po: -------------------------------------------------------------------------------- 1 | ## "msgid"s in this file come from POT (.pot) files. 2 | ## 3 | ## Do not add, change, or remove "msgid"s manually here as 4 | ## they're tied to the ones in the corresponding POT file 5 | ## (with the same domain). 6 | ## 7 | ## Use "mix gettext.extract --merge" or "mix gettext.merge" 8 | ## to merge POT files into PO files. 9 | msgid "" 10 | msgstr "" 11 | "Language: en\n" 12 | "Plural-Forms: nplurals=2\n" 13 | -------------------------------------------------------------------------------- /apps/mishka_translator/priv/gettext/en/LC_MESSAGES/user_captcha.po: -------------------------------------------------------------------------------- 1 | ## "msgid"s in this file come from POT (.pot) files. 2 | ## 3 | ## Do not add, change, or remove "msgid"s manually here as 4 | ## they're tied to the ones in the corresponding POT file 5 | ## (with the same domain). 6 | ## 7 | ## Use "mix gettext.extract --merge" or "mix gettext.merge" 8 | ## to merge POT files into PO files. 9 | msgid "" 10 | msgstr "" 11 | "Language: en\n" 12 | "Plural-Forms: nplurals=2\n" 13 | 14 | #, elixir-format 15 | #: lib/validation/google_recaptcha.ex:51 16 | msgid "برای ورود باید توکن دریافتی از گوگل را ارسال فرمایید در صورت تلاش مجدد و نمایش دوباره این پیام با پشتیبانی در تماس باشید." 17 | msgstr "" 18 | 19 | #, elixir-format 20 | #: lib/validation/google_recaptcha.ex:54 21 | msgid "درخواست شما قدیمی می باشد لطفا تلاش کنید در صورت تکرار صفحه را رفرش نمایید." 22 | msgstr "" 23 | 24 | #, elixir-format 25 | #: lib/validation/google_recaptcha.ex:53 26 | msgid "درخواست شما معتبر نمی باشد لطفا دوباره تلاش کنید" 27 | msgstr "" 28 | 29 | #, elixir-format 30 | #: lib/validation/google_recaptcha.ex:49 lib/validation/google_recaptcha.ex:50 31 | msgid "کد امنیتی ضد رباط شما ارسال نشده است لطفا در صورت نمایش این پیام با پشتیبانی وب سایت در تماس باشید." 32 | msgstr "" 33 | 34 | #, elixir-format 35 | #: lib/validation/google_recaptcha.ex:52 36 | msgid "کد ضد رباط شما درست نمی باشد و درخواست شما نا معتبر شناخته شده است لطفا دوباره تلاش کنید" 37 | msgstr "" 38 | -------------------------------------------------------------------------------- /apps/mishka_translator/priv/gettext/en/LC_MESSAGES/users.po: -------------------------------------------------------------------------------- 1 | ## "msgid"s in this file come from POT (.pot) files. 2 | ## 3 | ## Do not add, change, or remove "msgid"s manually here as 4 | ## they're tied to the ones in the corresponding POT file 5 | ## (with the same domain). 6 | ## 7 | ## Use "mix gettext.extract --merge" or "mix gettext.merge" 8 | ## to merge POT files into PO files. 9 | msgid "" 10 | msgstr "" 11 | "Language: en\n" 12 | "Plural-Forms: nplurals=2\n" 13 | -------------------------------------------------------------------------------- /apps/mishka_translator/priv/gettext/errors.pot: -------------------------------------------------------------------------------- 1 | ## This file is a PO Template file. 2 | ## 3 | ## "msgid"s here are often extracted from source code. 4 | ## Add new translations manually only if they're dynamic 5 | ## translations that can't be statically extracted. 6 | ## 7 | ## Run "mix gettext.extract" to bring this file up to 8 | ## date. Leave "msgstr"s empty as changing them here as no 9 | ## effect: edit them in PO (.po) files instead. 10 | msgid "" 11 | msgstr "" 12 | -------------------------------------------------------------------------------- /apps/mishka_translator/priv/gettext/fa/LC_MESSAGES/db_schema_public.po: -------------------------------------------------------------------------------- 1 | ## "msgid"s in this file come from POT (.pot) files. 2 | ## 3 | ## Do not add, change, or remove "msgid"s manually here as 4 | ## they're tied to the ones in the corresponding POT file 5 | ## (with the same domain). 6 | ## 7 | ## Use "mix gettext.extract --merge" or "mix gettext.merge" 8 | ## to merge POT files into PO files. 9 | msgid "" 10 | msgstr "" 11 | "Language: fa\n" 12 | "Plural-Forms: nplurals=1\n" 13 | 14 | #, elixir-format 15 | #: lib/schema/public/setting.ex:22 16 | msgid "برای این بخش قبلا تنظیمات وارد شده است." 17 | msgstr "" 18 | 19 | #, elixir-format 20 | #: lib/schema/public/setting.ex:21 21 | msgid "فیلد مذکور نمی تواند خالی باشد" 22 | msgstr "" 23 | -------------------------------------------------------------------------------- /apps/mishka_translator/priv/gettext/fa/LC_MESSAGES/default.po: -------------------------------------------------------------------------------- 1 | ## "msgid"s in this file come from POT (.pot) files. 2 | ## 3 | ## Do not add, change, or remove "msgid"s manually here as 4 | ## they're tied to the ones in the corresponding POT file 5 | ## (with the same domain). 6 | ## 7 | ## Use "mix gettext.extract --merge" or "mix gettext.merge" 8 | ## to merge POT files into PO files. 9 | msgid "" 10 | msgstr "" 11 | "Language: fa\n" 12 | "Plural-Forms: nplurals=1\n" 13 | 14 | #, elixir-format 15 | #: lib/mishka_html.ex:63 16 | msgid "Here is one string to html render" 17 | msgstr "" 18 | -------------------------------------------------------------------------------- /apps/mishka_translator/priv/gettext/fa/LC_MESSAGES/errors.po: -------------------------------------------------------------------------------- 1 | ## "msgid"s in this file come from POT (.pot) files. 2 | ## 3 | ## Do not add, change, or remove "msgid"s manually here as 4 | ## they're tied to the ones in the corresponding POT file 5 | ## (with the same domain). 6 | ## 7 | ## Use "mix gettext.extract --merge" or "mix gettext.merge" 8 | ## to merge POT files into PO files. 9 | msgid "" 10 | msgstr "" 11 | "Language: fa\n" 12 | "Plural-Forms: nplurals=1\n" 13 | -------------------------------------------------------------------------------- /apps/mishka_translator/priv/gettext/fa/LC_MESSAGES/user_captcha.po: -------------------------------------------------------------------------------- 1 | ## "msgid"s in this file come from POT (.pot) files. 2 | ## 3 | ## Do not add, change, or remove "msgid"s manually here as 4 | ## they're tied to the ones in the corresponding POT file 5 | ## (with the same domain). 6 | ## 7 | ## Use "mix gettext.extract --merge" or "mix gettext.merge" 8 | ## to merge POT files into PO files. 9 | msgid "" 10 | msgstr "" 11 | "Language: fa\n" 12 | "Plural-Forms: nplurals=1\n" 13 | 14 | #, elixir-format 15 | #: lib/validation/google_recaptcha.ex:51 16 | msgid "برای ورود باید توکن دریافتی از گوگل را ارسال فرمایید در صورت تلاش مجدد و نمایش دوباره این پیام با پشتیبانی در تماس باشید." 17 | msgstr "" 18 | 19 | #, elixir-format 20 | #: lib/validation/google_recaptcha.ex:54 21 | msgid "درخواست شما قدیمی می باشد لطفا تلاش کنید در صورت تکرار صفحه را رفرش نمایید." 22 | msgstr "" 23 | 24 | #, elixir-format 25 | #: lib/validation/google_recaptcha.ex:53 26 | msgid "درخواست شما معتبر نمی باشد لطفا دوباره تلاش کنید" 27 | msgstr "" 28 | 29 | #, elixir-format 30 | #: lib/validation/google_recaptcha.ex:49 lib/validation/google_recaptcha.ex:50 31 | msgid "کد امنیتی ضد رباط شما ارسال نشده است لطفا در صورت نمایش این پیام با پشتیبانی وب سایت در تماس باشید." 32 | msgstr "" 33 | 34 | #, elixir-format 35 | #: lib/validation/google_recaptcha.ex:52 36 | msgid "کد ضد رباط شما درست نمی باشد و درخواست شما نا معتبر شناخته شده است لطفا دوباره تلاش کنید" 37 | msgstr "" 38 | -------------------------------------------------------------------------------- /apps/mishka_translator/priv/gettext/fa/LC_MESSAGES/users.po: -------------------------------------------------------------------------------- 1 | ## "msgid"s in this file come from POT (.pot) files. 2 | ## 3 | ## Do not add, change, or remove "msgid"s manually here as 4 | ## they're tied to the ones in the corresponding POT file 5 | ## (with the same domain). 6 | ## 7 | ## Use "mix gettext.extract --merge" or "mix gettext.merge" 8 | ## to merge POT files into PO files. 9 | msgid "" 10 | msgstr "" 11 | "Language: fa\n" 12 | "Plural-Forms: nplurals=1\n" 13 | -------------------------------------------------------------------------------- /apps/mishka_translator/priv/gettext/user_captcha.pot: -------------------------------------------------------------------------------- 1 | ## This file is a PO Template file. 2 | ## 3 | ## "msgid"s here are often extracted from source code. 4 | ## Add new translations manually only if they're dynamic 5 | ## translations that can't be statically extracted. 6 | ## 7 | ## Run "mix gettext.extract" to bring this file up to 8 | ## date. Leave "msgstr"s empty as changing them here as no 9 | ## effect: edit them in PO (.po) files instead. 10 | msgid "" 11 | msgstr "" 12 | 13 | #, elixir-format 14 | #: lib/validation/google_recaptcha.ex:51 15 | msgid "برای ورود باید توکن دریافتی از گوگل را ارسال فرمایید در صورت تلاش مجدد و نمایش دوباره این پیام با پشتیبانی در تماس باشید." 16 | msgstr "" 17 | 18 | #, elixir-format 19 | #: lib/validation/google_recaptcha.ex:54 20 | msgid "درخواست شما قدیمی می باشد لطفا تلاش کنید در صورت تکرار صفحه را رفرش نمایید." 21 | msgstr "" 22 | 23 | #, elixir-format 24 | #: lib/validation/google_recaptcha.ex:53 25 | msgid "درخواست شما معتبر نمی باشد لطفا دوباره تلاش کنید" 26 | msgstr "" 27 | 28 | #, elixir-format 29 | #: lib/validation/google_recaptcha.ex:49 lib/validation/google_recaptcha.ex:50 30 | msgid "کد امنیتی ضد رباط شما ارسال نشده است لطفا در صورت نمایش این پیام با پشتیبانی وب سایت در تماس باشید." 31 | msgstr "" 32 | 33 | #, elixir-format 34 | #: lib/validation/google_recaptcha.ex:52 35 | msgid "کد ضد رباط شما درست نمی باشد و درخواست شما نا معتبر شناخته شده است لطفا دوباره تلاش کنید" 36 | msgstr "" 37 | -------------------------------------------------------------------------------- /apps/mishka_translator/priv/gettext/users.pot: -------------------------------------------------------------------------------- 1 | ## This file is a PO Template file. 2 | ## 3 | ## "msgid"s here are often extracted from source code. 4 | ## Add new translations manually only if they're dynamic 5 | ## translations that can't be statically extracted. 6 | ## 7 | ## Run "mix gettext.extract" to bring this file up to 8 | ## date. Leave "msgstr"s empty as changing them here as no 9 | ## effect: edit them in PO (.po) files instead. 10 | msgid "" 11 | msgstr "" 12 | -------------------------------------------------------------------------------- /apps/mishka_translator/test/mishka_translator_test.exs: -------------------------------------------------------------------------------- 1 | defmodule MishkaTranslatorTest do 2 | use ExUnit.Case 3 | doctest MishkaTranslator 4 | end 5 | -------------------------------------------------------------------------------- /apps/mishka_translator/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /apps/mishka_user/.formatter.exs: -------------------------------------------------------------------------------- 1 | # Used by "mix format" 2 | [ 3 | inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] 4 | ] 5 | -------------------------------------------------------------------------------- /apps/mishka_user/.gitignore: -------------------------------------------------------------------------------- 1 | # The directory Mix will write compiled artifacts to. 2 | /_build/ 3 | 4 | # If you run "mix test --cover", coverage assets end up here. 5 | /cover/ 6 | 7 | # The directory Mix downloads your dependencies sources to. 8 | /deps/ 9 | 10 | # Where third-party dependencies like ExDoc output generated docs. 11 | /doc/ 12 | 13 | # Ignore .fetch files in case you like to edit your project deps locally. 14 | /.fetch 15 | 16 | # If the VM crashes, it generates a dump, let's ignore it too. 17 | erl_crash.dump 18 | 19 | # Also ignore archive artifacts (built via "mix archive.build"). 20 | *.ez 21 | 22 | # Ignore package tarball (built via "mix hex.build"). 23 | mishka_user-*.tar 24 | 25 | 26 | # Temporary files for e.g. tests 27 | /tmp 28 | -------------------------------------------------------------------------------- /apps/mishka_user/README.md: -------------------------------------------------------------------------------- 1 | # MishkaUser 2 | 3 | **TODO: Add description** 4 | 5 | ## Installation 6 | 7 | If [available in Hex](https://hex.pm/docs/publish), the package can be installed 8 | by adding `mishka_user` to your list of dependencies in `mix.exs`: 9 | 10 | ```elixir 11 | def deps do 12 | [ 13 | {:mishka_user, "~> 0.1.0"} 14 | ] 15 | end 16 | ``` 17 | 18 | Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc) 19 | and published on [HexDocs](https://hexdocs.pm). Once published, the docs can 20 | be found at [https://hexdocs.pm/mishka_user](https://hexdocs.pm/mishka_user). 21 | 22 | -------------------------------------------------------------------------------- /apps/mishka_user/lib/acl/access.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaUser.Acl.Access do 2 | @separator ":" 3 | 4 | @type action() :: String.t() 5 | @type data_uuid() :: Ecto.UUID.t() 6 | 7 | @spec permittes?(action(), data_uuid() | binary) :: boolean 8 | def permittes?(action, user_id) do 9 | Enum.any?( 10 | MishkaUser.Acl.AclManagement.get_all(user_id).user_permission, 11 | fn %{value: permission} -> 12 | is_permitted?(action: action, permission: permission) 13 | end 14 | ) 15 | end 16 | 17 | @spec is_permitted?([{:action, action()} | {:permission, binary}, ...]) :: boolean 18 | def is_permitted?(action: action, permission: permission) do 19 | permission_chunks = String.split(permission, @separator) 20 | 21 | String.split(action, @separator, parts: length(permission_chunks)) 22 | |> check_permission(permission_chunks) 23 | end 24 | 25 | defp check_permission(action_chunks, permission_chunks) 26 | when length(permission_chunks) != length(action_chunks), 27 | do: false 28 | 29 | defp check_permission(action_chunks, permission_chunks) do 30 | Enum.zip(permission_chunks, action_chunks) 31 | |> Enum.find(fn {left, right} -> 32 | cond do 33 | left == "*" -> false 34 | left != right -> true 35 | true -> false 36 | end 37 | end) 38 | |> case do 39 | nil -> true 40 | _ -> false 41 | end 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /apps/mishka_user/lib/core_plugins/login/success_login.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaUser.CorePlugin.Login.SuccessLogin do 2 | alias MishkaInstaller.Reference.OnUserAfterLogin 3 | 4 | use MishkaInstaller.Hook, 5 | module: __MODULE__, 6 | behaviour: OnUserAfterLogin, 7 | event: :on_user_after_login, 8 | initial: [] 9 | 10 | @spec initial(list()) :: {:ok, OnUserAfterLogin.ref(), list()} 11 | def initial(args) do 12 | event = %PluginState{ 13 | name: "MishkaUser.CorePlugin.Login.SuccessLogin", 14 | event: Atom.to_string(@ref), 15 | priority: 1 16 | } 17 | 18 | Hook.register(event: event) 19 | {:ok, @ref, args} 20 | end 21 | 22 | @spec call(OnUserAfterLogin.t()) :: {:reply, OnUserAfterLogin.t()} 23 | def call(%OnUserAfterLogin{} = state) do 24 | create_user_permissions_on_state(state.user_info) 25 | {:reply, state} 26 | end 27 | 28 | defp create_user_permissions_on_state(user_info) do 29 | MishkaUser.Acl.AclManagement.save( 30 | %{ 31 | id: user_info.id, 32 | user_permission: MishkaUser.User.permissions(user_info.id), 33 | created: System.system_time(:second) 34 | }, 35 | user_info.id 36 | ) 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /apps/mishka_user/lib/core_plugins/login/success_logout.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaUser.CorePlugin.Login.SuccessLogout do 2 | alias MishkaInstaller.Reference.OnUserAfterLogout 3 | 4 | use MishkaInstaller.Hook, 5 | module: __MODULE__, 6 | behaviour: OnUserAfterLogout, 7 | event: :on_user_after_logout, 8 | initial: [] 9 | 10 | @spec initial(list()) :: {:ok, OnUserAfterLogout.ref(), list()} 11 | def initial(args) do 12 | event = %PluginState{ 13 | name: "MishkaUser.CorePlugin.Login.SuccessLogout", 14 | event: Atom.to_string(@ref), 15 | priority: 1 16 | } 17 | 18 | Hook.register(event: event) 19 | {:ok, @ref, args} 20 | end 21 | 22 | @spec call(OnUserAfterLogout.t()) :: {:reply, OnUserAfterLogout.t()} 23 | def call(%OnUserAfterLogout{} = state) do 24 | MishkaUser.Acl.AclManagement.delete(state.user_id) 25 | {:reply, state} 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /apps/mishka_user/lib/guardian/auth_error_handler.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaUser.AuthErrorHandler do 2 | import Plug.Conn 3 | @behaviour Guardian.Plug.ErrorHandler 4 | 5 | @impl Guardian.Plug.ErrorHandler 6 | def auth_error(conn, {type, _reason}, _opts) do 7 | body = 8 | Jason.encode!(%{ 9 | action: :access_token, 10 | system: :user, 11 | message: to_string(type) 12 | }) 13 | 14 | conn 15 | |> put_resp_content_type("application/json") 16 | |> send_resp(401, body) 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /apps/mishka_user/lib/guardian/auth_pipeline.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaUser.AuthPipeline do 2 | use Guardian.Plug.Pipeline, 3 | otp_app: :mishka_user, 4 | module: MishkaUser.Guardian, 5 | error_handler: MishkaUser.AuthErrorHandler 6 | 7 | plug(Guardian.Plug.VerifyHeader, claims: %{"typ" => "access"}, scheme: "Bearer") 8 | plug(Guardian.Plug.EnsureAuthenticated) 9 | plug(Guardian.Plug.LoadResource, ensure: true, allow_blank: true) 10 | end 11 | -------------------------------------------------------------------------------- /apps/mishka_user/lib/guardian/guardian.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaUser.Guardian do 2 | use Guardian, otp_app: :mishka_user 3 | 4 | @spec subject_for_token(atom | %{id: any}, any) :: {:ok, binary} 5 | def subject_for_token(resource, _claims) do 6 | # You can use any value for the subject of your token but 7 | # it should be useful in retrieving the resource later, see 8 | # how it being used on `resource_from_claims/1` function. 9 | # A unique `id` is a good subject, a non-unique email address 10 | # is a poor subject. 11 | sub = to_string(resource.id) 12 | {:ok, sub} 13 | end 14 | 15 | @spec subject_for_token :: {:error, :reason_for_error} 16 | def subject_for_token() do 17 | {:error, :reason_for_error} 18 | end 19 | 20 | @spec resource_from_claims(nil | maybe_improper_list | map) :: {:ok, %{id: any}} 21 | def resource_from_claims(claims) do 22 | # Here we'll look up our resource from the claims, the subject can be 23 | # found in the `"sub"` key. In `above subject_for_token/2` we returned 24 | # the resource id so here we'll rely on that to look it up. 25 | id = claims["sub"] 26 | resource = get_resource_by_id(id) 27 | {:ok, resource} 28 | end 29 | 30 | @spec resource_from_claims :: {:error, :reason_for_error} 31 | def resource_from_claims() do 32 | {:error, :reason_for_error} 33 | end 34 | 35 | @spec get_resource_by_id(binary()) :: %{id: any} 36 | def get_resource_by_id(id) do 37 | %{id: id} 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /apps/mishka_user/lib/mishka_user.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaUser do 2 | end 3 | -------------------------------------------------------------------------------- /apps/mishka_user/lib/mishka_user/application.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaUser.Application do 2 | # See https://hexdocs.pm/elixir/Application.html 3 | # for more information on OTP Applications 4 | @moduledoc false 5 | 6 | use Application 7 | @impl true 8 | def start(_type, _args) do 9 | # To support elixir 1.14, Ref: https://hexdocs.pm/elixir/main/Task.Supervisor.html#module-scalability-and-partitioning 10 | user_token_task = 11 | if Code.ensure_loaded?(PartitionSupervisor) do 12 | [{PartitionSupervisor, child_spec: Task.Supervisor, name: MishkaUser.Token.UserToken}] 13 | else 14 | [{Task.Supervisor, name: MishkaUser.Token.UserToken}] 15 | end 16 | 17 | children = 18 | user_token_task ++ 19 | [ 20 | MishkaUser.Token.TokenManagemnt, 21 | MishkaUser.Acl.AclManagement, 22 | {Finch, name: MyHttpClient}, 23 | %{ 24 | id: MishkaUser.CorePlugin.Login.SuccessLogin, 25 | start: {MishkaUser.CorePlugin.Login.SuccessLogin, :start_link, [[]]} 26 | }, 27 | %{ 28 | id: MishkaUser.CorePlugin.Login.SuccessLogout, 29 | start: {MishkaUser.CorePlugin.Login.SuccessLogout, :start_link, [[]]} 30 | } 31 | ] 32 | 33 | opts = [strategy: :one_for_one, name: MishkaUser.Supervisor] 34 | Supervisor.start_link(children, opts) 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /apps/mishka_user/lib/validation/user_input.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaUser.Validation do 2 | end 3 | -------------------------------------------------------------------------------- /apps/mishka_user/lib/worker/expire_random_code_worker.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaUser.Worker.ExpireRandomCodeWorker do 2 | use Oban.Worker, queue: :expire_token, max_attempts: 1 3 | require Logger 4 | 5 | @impl Oban.Worker 6 | def perform(%Oban.Job{args: %{"email" => email}}) do 7 | Logger.warn("Try to delete expired random code") 8 | MishkaUser.Validation.RandomCode.delete_code(email) 9 | :ok 10 | end 11 | 12 | def delete_random_code_scheduled( 13 | email, 14 | time \\ DateTime.utc_now() |> DateTime.add(600, :second) 15 | ) do 16 | %{email: email} 17 | |> MishkaUser.Worker.ExpireRandomCodeWorker.new(scheduled_at: time) 18 | |> Oban.insert() 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /apps/mishka_user/lib/worker/expire_token_worker.ex: -------------------------------------------------------------------------------- 1 | defmodule MishkaUser.Worker.ExpireTokenWorker do 2 | use Oban.Worker, queue: :expire_token, max_attempts: 1 3 | require Logger 4 | 5 | @impl Oban.Worker 6 | def perform(%Oban.Job{}) do 7 | Logger.warn("Try to delete expired token") 8 | MishkaUser.Token.TokenManagemnt.delete_expire_token() 9 | MishkaUser.Token.UserToken.delete_expire_token() 10 | :ok 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /apps/mishka_user/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule MishkaUser.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :mishka_user, 7 | version: "0.0.2", 8 | build_path: "../../_build", 9 | config_path: "../../config/config.exs", 10 | deps_path: "../../deps", 11 | lockfile: "../../mix.lock", 12 | elixir: "~> 1.13", 13 | compilers: [:gettext | Mix.compilers()], 14 | start_permanent: Mix.env() == :prod, 15 | deps: deps() 16 | ] 17 | end 18 | 19 | # Run "mix help compile.app" to learn about applications. 20 | def application do 21 | [ 22 | extra_applications: [:logger, :phoenix, :jose, :mishka_database], 23 | mod: {MishkaUser.Application, []} 24 | ] 25 | end 26 | 27 | # Run "mix help deps" to learn about dependencies. 28 | defp deps do 29 | [ 30 | {:mishka_installer, "~> 0.0.3"}, 31 | {:mishka_database, in_umbrella: true}, 32 | {:mishka_translator, in_umbrella: true}, 33 | {:plug, "~> 1.12"}, 34 | {:guardian, "~> 2.2"}, 35 | {:phoenix, "~> 1.6", override: true}, 36 | {:jose, "~> 1.11"}, 37 | {:finch, "~> 0.12.0"} 38 | ] 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /apps/mishka_user/test/mishka_user_test.exs: -------------------------------------------------------------------------------- 1 | defmodule MishkaUserTest do 2 | use ExUnit.Case, async: true 3 | doctest MishkaUser 4 | end 5 | -------------------------------------------------------------------------------- /apps/mishka_user/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /config/prod.secret.exs: -------------------------------------------------------------------------------- 1 | # In this file, we load production configuration and secrets 2 | # from environment variables. You can also hardcode secrets, 3 | # although such is generally not recommended and you have to 4 | # remember to add this file to your .gitignore. 5 | import Config 6 | 7 | secret_key_base_html = 8 | System.get_env("SECRET_KEY_BASE_HTML") || 9 | raise """ 10 | environment variable SECRET_KEY_BASE_HTML is missing. 11 | You can generate one by calling: mix phx.gen.secret 12 | """ 13 | 14 | secret_key_base_api = 15 | System.get_env("SECRET_KEY_BASE_API") || 16 | raise """ 17 | environment variable SECRET_KEY_BASE_API is missing. 18 | You can generate one by calling: mix phx.gen.secret 19 | """ 20 | 21 | config :mishka_html, MishkaHtmlWeb.Endpoint, 22 | url: [ 23 | scheme: System.get_env("PROTOCOL"), 24 | host: System.get_env("CMS_DOMAIN_NAME"), 25 | port: System.get_env("CMS_PORT") 26 | ], 27 | http: [ 28 | port: String.to_integer(System.get_env("PORT") || "4000"), 29 | transport_options: [socket_opts: [:inet6]] 30 | ], 31 | secret_key_base: secret_key_base_html 32 | 33 | config :mishka_api, MishkaApiWeb.Endpoint, 34 | url: [ 35 | scheme: System.get_env("PROTOCOL"), 36 | host: System.get_env("API_DOMAIN_NAME"), 37 | port: System.get_env("API_PORT") 38 | ], 39 | http: [ 40 | port: String.to_integer(System.get_env("PORT") || "4001"), 41 | transport_options: [socket_opts: [:inet6]] 42 | ], 43 | secret_key_base: secret_key_base_api 44 | 45 | # ## Using releases (Elixir v1.9+) 46 | # 47 | # If you are doing OTP releases, you need to instruct Phoenix 48 | # to start each relevant endpoint: 49 | # 50 | # config :mishka_cms_web, MishkaCmsWeb.Endpoint, server: true 51 | # 52 | # Then you can assemble a release by calling `mix release`. 53 | # See `mix help release` for more information. 54 | -------------------------------------------------------------------------------- /config/test.exs: -------------------------------------------------------------------------------- 1 | import Config 2 | 3 | # We don't run a server during test. If one is required, 4 | # you can enable the server option below. 5 | config :mishka_html, MishkaHtmlWeb.Endpoint, 6 | http: [port: 4002], 7 | server: false 8 | 9 | config :mishka_api, MishkaApiWeb.Endpoint, 10 | http: [port: 4003], 11 | server: false 12 | 13 | config :mishka_database, ecto_repos: [MishkaDatabase.Repo] 14 | 15 | config :mishka_database, MishkaDatabase.Repo, 16 | url: System.get_env("DATABASE_URL") || "ecto://postgres:postgres@localhost/mishka_test", 17 | pool: Ecto.Adapters.SQL.Sandbox, 18 | pool_size: 30, 19 | queue_target: 10000, 20 | show_sensitive_data_on_connection_error: true 21 | 22 | # Print only warnings and errors during test 23 | config :logger, level: :warn 24 | -------------------------------------------------------------------------------- /deployment/docker/bin/onefetch_linux: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahryarjb/mishka-cms/45563d985f98217f57e25829375835d93f540a6e/deployment/docker/bin/onefetch_linux -------------------------------------------------------------------------------- /deployment/docker/bin/onefetch_macos: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahryarjb/mishka-cms/45563d985f98217f57e25829375835d93f540a6e/deployment/docker/bin/onefetch_macos -------------------------------------------------------------------------------- /deployment/docker/dockers/docker-compose_dev_with_nginx.yml: -------------------------------------------------------------------------------- 1 | version: "3.9" 2 | 3 | services: 4 | mishka_nginx: 5 | image: nginx:1.20.1-alpine 6 | container_name: mishka_nginx 7 | restart: always 8 | ports: 9 | - "80:80" 10 | - "443:443" 11 | networks: 12 | netowrk: 13 | volumes: 14 | - ../etc/nginx/conf/:/etc/nginx/ 15 | - ../etc/nginx/cache:/var/nginx/cache 16 | - ../etc/ssl/dev:/etc/ssl/dev:ro 17 | - ../etc/ssl/letsencrypt:/etc/ssl/letsencrypt:ro 18 | - /etc/localtime:/etc/localtime:ro 19 | depends_on: 20 | - mishka_cms 21 | 22 | 23 | mishka_cms: 24 | image: mishkagroup/elixir_dev:1.13.3-alpine 25 | container_name: mishka_cms 26 | restart: always 27 | working_dir: /app 28 | command: sleep 365d 29 | hostname: mishka_cms 30 | networks: 31 | netowrk: 32 | env_file: 33 | - ../etc/.mishka_cms_env 34 | volumes: 35 | - ../../../:/app 36 | - /etc/localtime:/etc/localtime:ro 37 | depends_on: 38 | - mishka_db 39 | logging: 40 | driver: "json-file" 41 | options: 42 | max-size: "300m" 43 | 44 | 45 | mishka_db: 46 | image: mishkagroup/postgresql:3.14 47 | container_name: mishka_db 48 | hostname: mishka_db 49 | restart: always 50 | networks: 51 | netowrk: 52 | ports: 53 | - "5432:5432" 54 | env_file: 55 | - ../etc/.mishka_cms_env 56 | volumes: 57 | - database:/var/lib/postgresql/data 58 | - /etc/localtime:/etc/localtime:ro 59 | logging: 60 | driver: "json-file" 61 | options: 62 | max-size: "300m" 63 | 64 | 65 | networks: 66 | netowrk: 67 | 68 | 69 | volumes: 70 | database: 71 | -------------------------------------------------------------------------------- /deployment/docker/dockers/docker-compose_dev_without_nginx.yml: -------------------------------------------------------------------------------- 1 | version: "3.9" 2 | 3 | services: 4 | mishka_cms: 5 | image: mishkagroup/elixir_dev:1.13.3-alpine 6 | container_name: mishka_cms 7 | restart: always 8 | working_dir: /app 9 | command: sleep 365d 10 | hostname: mishka_cms 11 | networks: 12 | netowrk: 13 | ports: 14 | - "4000:4000" # for web 15 | - "4001:4001" # for api 16 | env_file: 17 | - ../etc/.mishka_cms_env 18 | volumes: 19 | - ../../../:/app 20 | - /etc/localtime:/etc/localtime:ro 21 | depends_on: 22 | - mishka_db 23 | logging: 24 | driver: "json-file" 25 | options: 26 | max-size: "300m" 27 | 28 | 29 | mishka_db: 30 | image: mishkagroup/postgresql:3.14 31 | container_name: mishka_db 32 | hostname: mishka_db 33 | restart: always 34 | networks: 35 | netowrk: 36 | ports: 37 | - "5432:5432" 38 | env_file: 39 | - ../etc/.mishka_cms_env 40 | volumes: 41 | - database:/var/lib/postgresql/data 42 | - /etc/localtime:/etc/localtime:ro 43 | logging: 44 | driver: "json-file" 45 | options: 46 | max-size: "300m" 47 | 48 | 49 | networks: 50 | netowrk: 51 | 52 | 53 | volumes: 54 | database: 55 | -------------------------------------------------------------------------------- /deployment/docker/dockers/docker-compose_without_nginx.yml: -------------------------------------------------------------------------------- 1 | version: "3.9" 2 | 3 | services: 4 | mishka_cms: 5 | image: mishak_app:latest 6 | container_name: mishka_cms 7 | restart: always 8 | working_dir: /app 9 | hostname: mishka_cms 10 | networks: 11 | netowrk: 12 | ports: 13 | - "4000:4000" # for web 14 | - "4001:4001" # for api 15 | environment: 16 | - DATABASE_USER=mishka_user 17 | - DATABASE_PASSWORD=mishka_password 18 | - DATABASE_HOST=mishka_db 19 | - DATABASE_PORT=5432 20 | - DATABASE_NAME=mishka_database 21 | volumes: 22 | - cms_extensions:/app/deployment/extensions 23 | - /etc/localtime:/etc/localtime:ro 24 | depends_on: 25 | - mishka_db 26 | logging: 27 | driver: "json-file" 28 | options: 29 | max-size: "300m" 30 | 31 | 32 | mishka_db: 33 | image: mishkagroup/postgresql:3.14 34 | container_name: mishka_db 35 | hostname: mishka_db 36 | restart: always 37 | networks: 38 | netowrk: 39 | environment: 40 | - POSTGRES_USER=postgres 41 | - POSTGRES_PASSWORD=postgres 42 | - DATABASE_USER=mishka_user 43 | - DATABASE_PASSWORD=mishka_password 44 | - DATABASE_NAME=mishka_database 45 | volumes: 46 | - database:/var/lib/postgresql/data 47 | - /etc/localtime:/etc/localtime:ro 48 | logging: 49 | driver: "json-file" 50 | options: 51 | max-size: "300m" 52 | 53 | 54 | networks: 55 | netowrk: 56 | 57 | 58 | volumes: 59 | cms_extensions: 60 | database: 61 | -------------------------------------------------------------------------------- /deployment/docker/dockers/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Note: !/bin/sh must be at the top of the line, 4 | # Alpine doesn't have bash so we need to use sh. 5 | # Docker entrypoint script. 6 | # Don't forget to give this file execution rights via `chmod +x entrypoint.sh` 7 | # which I've added to the Dockerfile but you could do this manually instead. 8 | 9 | # Wait until Postgres is ready before running the next step. 10 | while ! pg_isready -q -h $DATABASE_HOST -p $DATABASE_PORT -U $DATABASE_USER 11 | do 12 | echo "$(date) - waiting for database to start." 13 | sleep 2 14 | done 15 | 16 | 17 | print_db_name() 18 | { 19 | `PGPASSWORD=$DATABASE_PASSWORD psql -h $DATABASE_HOST 20 | -U $DATABASE_USER -Atqc "\\list $DATABASE_NAME"` 21 | } 22 | 23 | 24 | # Create the database if it doesn't exist. 25 | if [[ print_db_name ]]; then 26 | # Runs migrations, will skip if migrations are up to date. 27 | echo "Database $DATABASE_NAME exists, running migrations..." 28 | mix ecto.migrate 29 | echo "Migrations finished." 30 | mix run /app/apps/mishka_database/priv/repo/seeds.exs 31 | fi 32 | 33 | export MIX_ENV=prod 34 | 35 | # Start the server. 36 | exec mix phx.server -------------------------------------------------------------------------------- /deployment/docker/docs/mishka-logo.ans: -------------------------------------------------------------------------------- 1 | `- 2 | -: 3 | -:` `:- 4 | .` `:/y: `. 5 | ``` `+. +- `` 6 | `:-` :- `+ -:. 7 | -``-` 8 | `. 9 | .://+. 10 | `.:::os:/+. 11 | ....:-` ` `++`./s+. 12 | `:++. ` `:ss/-y`++` 13 | .++- :: :/+` .: -s: 14 | :+/` ` :. o/.`.` +y- 15 | `:/. +`od/ ./ y:/` 16 | `.` :: `` ./`o `:- 17 | -+/.` `` `+/ `-` 18 | `y`+ `-.`/: `` 19 | o/:/ -/-y 20 | :oy: `/h: 21 | `+y+oooo+o++. 22 | `//--:+o..++. 23 | `s. .+``--.++. 24 | -yy:-/ ./..++` 25 | `-//:y-.-::. /::+s- 26 | .::--` 27 | -------------------------------------------------------------------------------- /deployment/docker/etc/nginx/conf/conf.d/default.conf: -------------------------------------------------------------------------------- 1 | server { 2 | server_name _; 3 | return 403; 4 | } -------------------------------------------------------------------------------- /deployment/docker/etc/nginx/conf/conf.d/mishka_api.conf: -------------------------------------------------------------------------------- 1 | upstream api { 2 | server mishka_cms:4001; 3 | } 4 | 5 | server { 6 | listen MISHKA_API_PORT; 7 | server_name MISHKA_API_DOMAIN_NAME; 8 | 9 | #include /etc/nginx/ssl.conf; 10 | 11 | # gzip config 12 | gzip on; 13 | gzip_vary on; 14 | gzip_min_length 1000; 15 | gzip_comp_level 5; 16 | gzip_types application/json text/css application/x-javascript application/javascript image/svg+xml; 17 | gzip_proxied any; 18 | 19 | # logs 20 | error_log /dev/stdout; 21 | access_log /dev/stdout; 22 | 23 | 24 | location / { 25 | proxy_set_header X-Real-IP $remote_addr; 26 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 27 | # fix websocket in phoenix 28 | proxy_http_version 1.1; 29 | proxy_set_header Host $host; 30 | proxy_pass http://api; 31 | proxy_set_header Upgrade $http_upgrade; 32 | proxy_set_header Connection "upgrade"; 33 | 34 | proxy_redirect http://api https://MISHKA_API_DOMAIN_NAME/; 35 | } 36 | } -------------------------------------------------------------------------------- /deployment/docker/etc/nginx/conf/conf.d/mishka_cms.conf: -------------------------------------------------------------------------------- 1 | upstream cms { 2 | server mishka_cms:4000; 3 | } 4 | 5 | server { 6 | listen MISHKA_CMS_PORT; 7 | server_name MISHKA_CMS_DOMAIN_NAME; 8 | 9 | #include /etc/nginx/ssl.conf; 10 | 11 | # gzip config 12 | gzip on; 13 | gzip_vary on; 14 | gzip_min_length 1000; 15 | gzip_comp_level 5; 16 | gzip_types application/json text/css application/x-javascript application/javascript image/svg+xml; 17 | gzip_proxied any; 18 | 19 | # logs 20 | error_log /dev/stdout; 21 | access_log /dev/stdout; 22 | 23 | 24 | location / { 25 | proxy_set_header X-Real-IP $remote_addr; 26 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 27 | # fix websocket in phoenix 28 | proxy_http_version 1.1; 29 | proxy_set_header Host $host; 30 | proxy_pass http://cms; 31 | proxy_set_header Upgrade $http_upgrade; 32 | proxy_set_header Connection "upgrade"; 33 | 34 | proxy_redirect http://cms https://MISHKA_CMS_DOMAIN_NAME/; 35 | 36 | } 37 | 38 | 39 | } -------------------------------------------------------------------------------- /deployment/docker/etc/nginx/conf/fastcgi.conf: -------------------------------------------------------------------------------- 1 | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; 2 | fastcgi_param QUERY_STRING $query_string; 3 | fastcgi_param REQUEST_METHOD $request_method; 4 | fastcgi_param CONTENT_TYPE $content_type; 5 | fastcgi_param CONTENT_LENGTH $content_length; 6 | 7 | fastcgi_param SCRIPT_NAME $fastcgi_script_name; 8 | fastcgi_param REQUEST_URI $request_uri; 9 | fastcgi_param DOCUMENT_URI $document_uri; 10 | fastcgi_param DOCUMENT_ROOT $document_root; 11 | fastcgi_param SERVER_PROTOCOL $server_protocol; 12 | fastcgi_param REQUEST_SCHEME $scheme; 13 | fastcgi_param HTTPS $https if_not_empty; 14 | 15 | fastcgi_param GATEWAY_INTERFACE CGI/1.1; 16 | fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; 17 | 18 | fastcgi_param REMOTE_ADDR $remote_addr; 19 | fastcgi_param REMOTE_PORT $remote_port; 20 | fastcgi_param SERVER_ADDR $server_addr; 21 | fastcgi_param SERVER_PORT $server_port; 22 | fastcgi_param SERVER_NAME $server_name; 23 | 24 | # PHP only, required if PHP was built with --enable-force-cgi-redirect 25 | fastcgi_param REDIRECT_STATUS 200; -------------------------------------------------------------------------------- /deployment/docker/etc/nginx/conf/fastcgi_params: -------------------------------------------------------------------------------- 1 | fastcgi_param QUERY_STRING $query_string; 2 | fastcgi_param REQUEST_METHOD $request_method; 3 | fastcgi_param CONTENT_TYPE $content_type; 4 | fastcgi_param CONTENT_LENGTH $content_length; 5 | 6 | fastcgi_param SCRIPT_NAME $fastcgi_script_name; 7 | fastcgi_param REQUEST_URI $request_uri; 8 | fastcgi_param DOCUMENT_URI $document_uri; 9 | fastcgi_param DOCUMENT_ROOT $document_root; 10 | fastcgi_param SERVER_PROTOCOL $server_protocol; 11 | fastcgi_param REQUEST_SCHEME $scheme; 12 | fastcgi_param HTTPS $https if_not_empty; 13 | 14 | fastcgi_param GATEWAY_INTERFACE CGI/1.1; 15 | fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; 16 | 17 | fastcgi_param REMOTE_ADDR $remote_addr; 18 | fastcgi_param REMOTE_PORT $remote_port; 19 | fastcgi_param SERVER_ADDR $server_addr; 20 | fastcgi_param SERVER_PORT $server_port; 21 | fastcgi_param SERVER_NAME $server_name; 22 | 23 | # PHP only, required if PHP was built with --enable-force-cgi-redirect 24 | fastcgi_param REDIRECT_STATUS 200; -------------------------------------------------------------------------------- /deployment/docker/etc/nginx/conf/modules: -------------------------------------------------------------------------------- 1 | /usr/lib/nginx/modules -------------------------------------------------------------------------------- /deployment/docker/etc/nginx/conf/nginx.conf: -------------------------------------------------------------------------------- 1 | user nginx; 2 | worker_processes auto; 3 | 4 | pid /var/run/nginx.pid; 5 | 6 | events { 7 | worker_connections 1024; 8 | } 9 | 10 | 11 | http { 12 | include /etc/nginx/mime.types; 13 | default_type application/octet-stream; 14 | 15 | log_format main '$remote_addr - $remote_user [$time_local] "$request" ' 16 | '$status $body_bytes_sent "$http_referer" ' 17 | '"$http_user_agent" "$http_x_forwarded_for"'; 18 | 19 | 20 | client_max_body_size 8M; 21 | 22 | # avoid attack 23 | limit_req_zone $binary_remote_addr zone=flood:10m rate=12r/s; 24 | limit_req_zone $binary_remote_addr zone=bot:10m rate=200r/m; 25 | limit_req_status 429; 26 | limit_conn_zone $binary_remote_addr zone=connperip:10m; 27 | limit_conn_status 429; 28 | limit_rate 1024k; 29 | 30 | 31 | keepalive_timeout 65; 32 | 33 | 34 | server_tokens off; 35 | add_header X-Frame-Options SAMEORIGIN; 36 | # add_header X-Frame-Options DENY; 37 | add_header X-Content-Type-Options nosniff; 38 | add_header X-XSS-Protection "1; mode=block"; 39 | 40 | 41 | server { 42 | listen 80 default_server; 43 | listen [::]:80 default_server; 44 | return 301 https://$host$request_uri; 45 | } 46 | 47 | include /etc/nginx/conf.d/*.conf; 48 | } -------------------------------------------------------------------------------- /deployment/docker/etc/nginx/conf/sample_conf/mishka_api.conf: -------------------------------------------------------------------------------- 1 | upstream api { 2 | server mishka_cms:4001; 3 | } 4 | 5 | server { 6 | listen MISHKA_API_PORT; 7 | server_name MISHKA_API_DOMAIN_NAME; 8 | 9 | #include /etc/nginx/ssl.conf; 10 | 11 | # gzip config 12 | gzip on; 13 | gzip_vary on; 14 | gzip_min_length 1000; 15 | gzip_comp_level 5; 16 | gzip_types application/json text/css application/x-javascript application/javascript image/svg+xml; 17 | gzip_proxied any; 18 | 19 | # logs 20 | error_log /dev/stdout; 21 | access_log /dev/stdout; 22 | 23 | 24 | location / { 25 | proxy_set_header X-Real-IP $remote_addr; 26 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 27 | # fix websocket in phoenix 28 | proxy_http_version 1.1; 29 | proxy_set_header Host $host; 30 | proxy_pass http://api; 31 | proxy_set_header Upgrade $http_upgrade; 32 | proxy_set_header Connection "upgrade"; 33 | 34 | proxy_redirect http://api https://MISHKA_API_DOMAIN_NAME/; 35 | } 36 | } -------------------------------------------------------------------------------- /deployment/docker/etc/nginx/conf/sample_conf/mishka_cms.conf: -------------------------------------------------------------------------------- 1 | upstream cms { 2 | server mishka_cms:4000; 3 | } 4 | 5 | server { 6 | listen MISHKA_CMS_PORT; 7 | server_name MISHKA_CMS_DOMAIN_NAME; 8 | 9 | #include /etc/nginx/ssl.conf; 10 | 11 | # gzip config 12 | gzip on; 13 | gzip_vary on; 14 | gzip_min_length 1000; 15 | gzip_comp_level 5; 16 | gzip_types application/json text/css application/x-javascript application/javascript image/svg+xml; 17 | gzip_proxied any; 18 | 19 | # logs 20 | error_log /dev/stdout; 21 | access_log /dev/stdout; 22 | 23 | 24 | location / { 25 | proxy_set_header X-Real-IP $remote_addr; 26 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 27 | # fix websocket in phoenix 28 | proxy_http_version 1.1; 29 | proxy_set_header Host $host; 30 | proxy_pass http://cms; 31 | proxy_set_header Upgrade $http_upgrade; 32 | proxy_set_header Connection "upgrade"; 33 | 34 | proxy_redirect http://cms https://MISHKA_CMS_DOMAIN_NAME/; 35 | 36 | } 37 | 38 | 39 | } -------------------------------------------------------------------------------- /deployment/docker/etc/nginx/conf/sample_conf/ssl_dev.conf: -------------------------------------------------------------------------------- 1 | ssl_certificate /etc/ssl/dev/server_example.crt; 2 | ssl_certificate_key /etc/ssl/dev/server_example.key; 3 | ssl_trusted_certificate /etc/ssl/letsencrypt/lets-encrypt-x3-cross-signed.pem; 4 | ssl_dhparam /etc/ssl/letsencrypt/dhparam2048.pem; 5 | ssl_ecdh_curve secp384r1; 6 | ssl_session_cache shared:SSL:50m; 7 | ssl_session_timeout 1d; 8 | ssl_session_tickets off; 9 | ssl_prefer_server_ciphers on; 10 | ssl_protocols TLSv1 TLSv1.1 TLSv1.2; 11 | ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA'; 12 | resolver 8.8.8.8 8.8.4.4; 13 | ssl_stapling_verify on; 14 | ssl_buffer_size 4k; 15 | add_header Strict-Transport-Security "max-age=31536000; includeSubdomains"; 16 | -------------------------------------------------------------------------------- /deployment/docker/etc/nginx/conf/sample_conf/ssl_prod.conf: -------------------------------------------------------------------------------- 1 | ssl_certificate /etc/ssl/prod/letsencrypt/live/SITE_NAME/fullchain.pem; 2 | ssl_certificate_key /etc/ssl/prod/letsencrypt/live/SITE_NAME/privkey.pem; 3 | ssl_trusted_certificate /etc/ssl/letsencrypt/lets-encrypt-x3-cross-signed.pem; 4 | ssl_dhparam /etc/ssl/letsencrypt/dhparam2048.pem; 5 | ssl_ecdh_curve secp384r1; 6 | ssl_session_cache shared:SSL:50m; 7 | ssl_session_timeout 1d; 8 | ssl_session_tickets off; 9 | ssl_prefer_server_ciphers on; 10 | ssl_protocols TLSv1 TLSv1.1 TLSv1.2; 11 | ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA'; 12 | resolver 8.8.8.8 8.8.4.4; 13 | ssl_stapling on; 14 | ssl_stapling_verify on; 15 | ssl_buffer_size 4k; 16 | add_header Strict-Transport-Security "max-age=31536000; includeSubdomains"; 17 | -------------------------------------------------------------------------------- /deployment/docker/etc/nginx/conf/scgi_params: -------------------------------------------------------------------------------- 1 | scgi_param REQUEST_METHOD $request_method; 2 | scgi_param REQUEST_URI $request_uri; 3 | scgi_param QUERY_STRING $query_string; 4 | scgi_param CONTENT_TYPE $content_type; 5 | 6 | scgi_param DOCUMENT_URI $document_uri; 7 | scgi_param DOCUMENT_ROOT $document_root; 8 | scgi_param SCGI 1; 9 | scgi_param SERVER_PROTOCOL $server_protocol; 10 | scgi_param REQUEST_SCHEME $scheme; 11 | scgi_param HTTPS $https if_not_empty; 12 | 13 | scgi_param REMOTE_ADDR $remote_addr; 14 | scgi_param REMOTE_PORT $remote_port; 15 | scgi_param SERVER_PORT $server_port; 16 | scgi_param SERVER_NAME $server_name; -------------------------------------------------------------------------------- /deployment/docker/etc/nginx/conf/ssl.conf: -------------------------------------------------------------------------------- 1 | ssl_certificate /etc/ssl/dev/server_example.crt; 2 | ssl_certificate_key /etc/ssl/dev/server_example.key; 3 | ssl_trusted_certificate /etc/ssl/letsencrypt/lets-encrypt-x3-cross-signed.pem; 4 | ssl_dhparam /etc/ssl/letsencrypt/dhparam2048.pem; 5 | ssl_ecdh_curve secp384r1; 6 | ssl_session_cache shared:SSL:50m; 7 | ssl_session_timeout 1d; 8 | ssl_session_tickets off; 9 | ssl_prefer_server_ciphers on; 10 | ssl_protocols TLSv1 TLSv1.1 TLSv1.2; 11 | ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA'; 12 | resolver 8.8.8.8 8.8.4.4; 13 | ssl_stapling_verify on; 14 | ssl_buffer_size 4k; 15 | add_header Strict-Transport-Security "max-age=31536000; includeSubdomains"; 16 | -------------------------------------------------------------------------------- /deployment/docker/etc/nginx/conf/uwsgi_params: -------------------------------------------------------------------------------- 1 | uwsgi_param QUERY_STRING $query_string; 2 | uwsgi_param REQUEST_METHOD $request_method; 3 | uwsgi_param CONTENT_TYPE $content_type; 4 | uwsgi_param CONTENT_LENGTH $content_length; 5 | 6 | uwsgi_param REQUEST_URI $request_uri; 7 | uwsgi_param PATH_INFO $document_uri; 8 | uwsgi_param DOCUMENT_ROOT $document_root; 9 | uwsgi_param SERVER_PROTOCOL $server_protocol; 10 | uwsgi_param REQUEST_SCHEME $scheme; 11 | uwsgi_param HTTPS $https if_not_empty; 12 | 13 | uwsgi_param REMOTE_ADDR $remote_addr; 14 | uwsgi_param REMOTE_PORT $remote_port; 15 | uwsgi_param SERVER_PORT $server_port; 16 | uwsgi_param SERVER_NAME $server_name; 17 | -------------------------------------------------------------------------------- /deployment/docker/etc/ssl/dev/rootCA_example.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIID/TCCAuWgAwIBAgIUcgHeoOVz1mi7U0MgEAXvENfMRGcwDQYJKoZIhvcNAQEL 3 | BQAwgY0xCzAJBgNVBAYTAklSMQ8wDQYDVQQIDAZUZWhyYW4xDzANBgNVBAcMBlRl 4 | aHJhbjERMA8GA1UECgwIVHJhbmdlbGwxETAPBgNVBAsMCFRyYW5nZWxsMRQwEgYD 5 | VQQDDAtleGFtcGxlLmNvbTEgMB4GCSqGSIb3DQEJARYRaW5mb0B0cmFuZ2VsbC5j 6 | b20wHhcNMjExMTExMjE0OTM0WhcNMzExMTA5MjE0OTM0WjCBjTELMAkGA1UEBhMC 7 | SVIxDzANBgNVBAgMBlRlaHJhbjEPMA0GA1UEBwwGVGVocmFuMREwDwYDVQQKDAhU 8 | cmFuZ2VsbDERMA8GA1UECwwIVHJhbmdlbGwxFDASBgNVBAMMC2V4YW1wbGUuY29t 9 | MSAwHgYJKoZIhvcNAQkBFhFpbmZvQHRyYW5nZWxsLmNvbTCCASIwDQYJKoZIhvcN 10 | AQEBBQADggEPADCCAQoCggEBAMDfsT7nHDmLuL454ASUR86+6L+nXy2UTbEKAnEW 11 | eyx2rXBd42dMVfZsSWSRvVg0KKcVP6RC2883J/Q3thy9UYS8mgP3YrZ6CQ/yHvk9 12 | 1DK9za5kLYiHC3O21kCuGDUswWa8oiQp9x41K95FvduQpw2Cj5rHzhWIzNWtRSBJ 13 | h3n/BSog82NScicJkluuy0DR+gdzrhy3Q3dfH4WinmF7ieVNvQ40pCslcndMq+2S 14 | jw8SFKwPEsE79AhOoU7ok3vudr0KrZrxjcJ5VCblA+0+3yShYYOWpv59bD2yM+5T 15 | fTpdDb74tJH/c7DuxBBntrU/FobdMnMDOrrkA92twfpJip8CAwEAAaNTMFEwHQYD 16 | VR0OBBYEFM97sLvh6XO6s+kY1l5R9NX9Kdt/MB8GA1UdIwQYMBaAFM97sLvh6XO6 17 | s+kY1l5R9NX9Kdt/MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEB 18 | AKtDSiyEd+33DJgTSXfOo4GiRJoS98Zs80DotVW1B4OraL1iHYjWSc76Ysn6/pZh 19 | qSi1Rf5ngENQWpwDcglVWxYJsEhoYe2Ya3rhe+UwEKxppDnLoQFQrU/Lci7TaYg3 20 | NOAo4aKP2PJhYtoong2dzbuPC9PkMut1JqLVV7ceCrJ+N7/Mbnc6hIoGu6yaofeH 21 | 47R83jvFy4/1Mqo49xbp62X9ALVMJfaCsxx0QT7Xsqrk5Xaa6ebJUC8WrHwbi+YF 22 | oPFCwUwTLNXIqFirbWB4ItizQ889jytzKY2f26aj/gknhhVhZh79Kq00+Y8KTnpS 23 | mwtY1lo9IXT+Kk1GdeVRXCA= 24 | -----END CERTIFICATE----- 25 | -------------------------------------------------------------------------------- /deployment/docker/etc/ssl/dev/server_example.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIEHzCCAwegAwIBAgIUfujPbRrlarPB/6ODXAx4o7MaI/IwDQYJKoZIhvcNAQEL 3 | BQAwgY0xCzAJBgNVBAYTAklSMQ8wDQYDVQQIDAZUZWhyYW4xDzANBgNVBAcMBlRl 4 | aHJhbjERMA8GA1UECgwIVHJhbmdlbGwxETAPBgNVBAsMCFRyYW5nZWxsMRQwEgYD 5 | VQQDDAtleGFtcGxlLmNvbTEgMB4GCSqGSIb3DQEJARYRaW5mb0B0cmFuZ2VsbC5j 6 | b20wHhcNMjExMTExMjE1MDMxWhcNMzExMTA5MjE1MDMxWjCBjTELMAkGA1UEBhMC 7 | SVIxDzANBgNVBAgMBlRlaHJhbjEPMA0GA1UEBwwGVGVocmFuMREwDwYDVQQKDAhU 8 | cmFuZ2VsbDERMA8GA1UECwwIVHJhbmdlbGwxIDAeBgkqhkiG9w0BCQEWEWluZm9A 9 | dHJhbmdlbGwuY29tMRQwEgYDVQQDDAtleGFtcGxlLmNvbTCCASIwDQYJKoZIhvcN 10 | AQEBBQADggEPADCCAQoCggEBAMX2rLwmh6AbIw3SzGbgSoybj7tzn/QoXPbHWZ0w 11 | qPI7eGvpe/FD7+WZLSKMAYxccOuTOdRmnAIVtcO1/ckhwerhFcpnAfiSQeGgEbOI 12 | zDWqJA/XJyGAGJXGjx0tEh18VXTUQ8rJRRa6/L8MaQExGQzgoakEvHkXXBAv1tkq 13 | CwSbZOof3dPtkIaffd04Yt8hXV2ECJKwBb14B5Mw1eSU2CWAicLpLBDgh6PZe40y 14 | 0sQGxBm+61W51rQpc+C2lY9RpnHzsr20lz6QgiBBkp8mqEJiMN+tqItPv8pWcVI2 15 | v1er+Nh61lplBADkzkFA3C7ZfRry1Jg0dfhItJSQwKs/Sq8CAwEAAaN1MHMwHwYD 16 | VR0jBBgwFoAUz3uwu+Hpc7qz6RjWXlH01f0p238wCQYDVR0TBAIwADALBgNVHQ8E 17 | BAMCBPAwOAYDVR0RBDEwL4ILZXhhbXBsZS5jb22CD2Ntcy5leGFtcGxlLmNvbYIP 18 | YXBpLmV4YW1wbGUuY29tMA0GCSqGSIb3DQEBCwUAA4IBAQBsu3rdlKtnrloodkc9 19 | CSahnMi/+kDj8E+dFteHmxJD1nI3FGvtfgzahQApzpavO8TFr+0Jf3JgnzH/6I8d 20 | Az+sq/23zcLQnZeykVSXNJzy+pQRIlTrzuYnViVj/g1fJKGneyI27H+sWTB7w0Dl 21 | Mtc1Rwu9eqvuEBEOAk/pRPM2sTNAnfYCYDqjXSJv0Njl69hyPkru3us8pVJHH0No 22 | ERPH/MDlZzCsMLT/GIbD63RmG71k/4Zi6LxWSmUztB+lLQ9xGa0Eax3pGK96tYR6 23 | 6yo/BeFsWISy0GjAhf7vwdxBQE0UShRbXQFSwbsHPOjXDGFF++INGrZ0p8C5T/u5 24 | VKId 25 | -----END CERTIFICATE----- 26 | -------------------------------------------------------------------------------- /deployment/docker/etc/ssl/dev/server_example.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDF9qy8JoegGyMN 3 | 0sxm4EqMm4+7c5/0KFz2x1mdMKjyO3hr6XvxQ+/lmS0ijAGMXHDrkznUZpwCFbXD 4 | tf3JIcHq4RXKZwH4kkHhoBGziMw1qiQP1ychgBiVxo8dLRIdfFV01EPKyUUWuvy/ 5 | DGkBMRkM4KGpBLx5F1wQL9bZKgsEm2TqH93T7ZCGn33dOGLfIV1dhAiSsAW9eAeT 6 | MNXklNglgInC6SwQ4Iej2XuNMtLEBsQZvutVuda0KXPgtpWPUaZx87K9tJc+kIIg 7 | QZKfJqhCYjDfraiLT7/KVnFSNr9Xq/jYetZaZQQA5M5BQNwu2X0a8tSYNHX4SLSU 8 | kMCrP0qvAgMBAAECggEBAKVX/LpBrDHLuKGJGXQrjdiW7ZvxXP3+4Ha11mF2DQYV 9 | KeVn5D+FMM+h+pLKQVjMtPvtwfVnppIPM/u8+7WMXn0hdqPRGVJWRnR+z4oWjgmc 10 | i/Y3C9XtOZuPdmU2CdVazb2AtQagyPXNQ+EGKoX2Tif1TtDuxcSWACz86AQGG6HB 11 | +J61FgWQP8kgFD8dgtpQh2XLxswhpRg0WwR1zbviN8Kqf7X9ADIyF9piJ24zJwH2 12 | qfRp6uYXeDJ6eGkcaWZBQcE0LXFJfx8T5bjteFfKBNZYjdgkPPO1uqk6VGMU78XE 13 | /HL+ydlwNK+5O8leY36wDFKtlZv2hdjMoOUuuHcdjgECgYEA4gUFtCu11CHBKyow 14 | Oh8SuhRAz4oYeTKcLVjv6a55nADT8oDuCR70t6mq2UioTDKuedPyGRo30lHcrIX+ 15 | JuhZmdjuSzH00Ou/KkI7kOQ+V+4sN3skbhEGiYEI+5I2PwSLCyxbCvUHyrPR1PcA 16 | ivMS0jS6r2u4qb5/mle6GPPaRy8CgYEA4DjzHf/ZzN5kRS2AFRu+mZqH7CzRDKtd 17 | hDBahdGEeXiTQAOUWTDJIPyrkkfb4yxKI3DMpY8z3bT23uPef8taACVYSLzLliF9 18 | vvWWzf07hVpjGGWVUU0C2ihkTam77Pkwk3dCzSAU2D95as/9J3Iaqv+wknRdohTT 19 | uss9gAn6VIECgYBeN0e8ZigiqHt0ed6mq8NLrBukJ+Wxx+YQhS1lFOT+od24DgSr 20 | 6qqKUQC2GLKHKO1QPYiC7Enus08w354lK+AF4Mbcs5Ng75S9keRwrqRKVS87ZWq3 21 | MwOtmAtdiwJv3H31h2TgOWopFjJW+yvPwCnNVEupylas84sPlJgvxJ7t4wKBgQDN 22 | Xvw3Pw/D2PKodit5qgbi9CqJBOeZHiCyogNXzHb1N55PpLetFcUzBJs1icH6iqeB 23 | XKDlB4wvBsCTmM1D6gMOXSZGwT4LzbM6RAGTvN1WoFphjzG73Li/Dv4IMG4jeH6o 24 | ozS5YygUhdb1IXozNgz9EOMu0YytlzvzPJKhAwKZgQKBgCR/bGijIB/Hlf8+EcT5 25 | inBx15VE9Gli8FgavgJ8lhZpoXPwBQ5bvrCgaQipD5Dau4pXMOhjuF0BMjr1Xjnv 26 | hViAAWC+pSc09RnEMrVwndN+If5DAxU63ZoeBFP0CTWVSlxcsa3ugfpWAXS57afu 27 | 83HtIMRAzWKGmNctvfQ4b/nz 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /deployment/docker/etc/ssl/letsencrypt/dhparam2048.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN DH PARAMETERS----- 2 | MIIBCAKCAQEAjQnY67buJizZHHpvyGE6eqXuofxuZdK6KUWIMx7G8aQKWCO0JVZU 3 | GNLxBQAOEZ2QxYOUK64Ks1HKHWWR+yQEdfoX37OwxhBQd6X9q2KgGisCXEzf+/8r 4 | /ytiQr8emTJ0mB800jiSTMaDIx5MkNd8rUPVkOqwB5oyPniu5IcpIVeaAlPVqOzn 5 | tj85uTZcoRfH5tZTKz524kPDJwpOl4/OCf+hVdcsQl2ryW48d7V5hWXcB6szgc2V 6 | VVRoDjUE/SvCm4YY3s5KodFik3z1sfDSkGtr534Gucr4/yZ+WNDgbiaO9KWgK+4L 7 | S2qJVYINAJmuHZsoqwlf0HmjjHFzsQec0wIBAg== 8 | -----END DH PARAMETERS----- 9 | -------------------------------------------------------------------------------- /deployment/docker/etc/ssl/letsencrypt/lets-encrypt-x3-cross-signed.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/ 3 | MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT 4 | DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow 5 | SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT 6 | GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC 7 | AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF 8 | q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8 9 | SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0 10 | Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA 11 | a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj 12 | /PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T 13 | AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG 14 | CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv 15 | bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k 16 | c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw 17 | VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC 18 | ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz 19 | MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu 20 | Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF 21 | AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo 22 | uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/ 23 | wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu 24 | X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG 25 | PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6 26 | KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg== 27 | -----END CERTIFICATE----- -------------------------------------------------------------------------------- /deployment/docker/src/variables.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # color variables 4 | Red='\033[0;31m' 5 | Black='\033[0;30m' 6 | Dark_Gray='\033[1;30m' 7 | Light_Red='\033[1;31m' 8 | Green='\033[0;32m' 9 | Light_Green='\033[1;32m' 10 | Brown_Orange='\033[0;33m' 11 | Yellow='\033[1;33m' 12 | Blue='\033[0;34m' 13 | Light_Blue='\033[1;34m' 14 | Purple='\033[0;35m' 15 | Light_Purple='\033[1;35m' 16 | Cyan='\033[0;36m' 17 | Light_Cyan='\033[1;36m' 18 | Light_Gray='\033[0;37m' 19 | White='\033[1;37m' 20 | NC='\033[0m' # No Color 21 | SPACE=`tput setab 7` 22 | END_SPACE=`tput sgr 0` 23 | -------------------------------------------------------------------------------- /mix.exs: -------------------------------------------------------------------------------- 1 | defmodule MishkaCms.Umbrella.MixProject do 2 | use Mix.Project 3 | 4 | @version "0.0.2" 5 | 6 | def project do 7 | [ 8 | apps_path: "apps", 9 | version: @version, 10 | start_permanent: Mix.env() == :prod, 11 | deps: deps(), 12 | aliases: aliases(), 13 | name: "MishkaCms", 14 | source_url: "https://github.com/mishka-group/mishka-cms", 15 | homepage_url: "https://mishka.group/", 16 | description: description(), 17 | package: package(), 18 | dialyzer: [ 19 | list_unused_filters: true 20 | ], 21 | docs: [ 22 | # The main page in the docs 23 | main: "MishkaCms" 24 | # logo: "path/to/logo.png", 25 | # extras: ["README.md"] 26 | ] 27 | ] 28 | end 29 | 30 | defp deps do 31 | [ 32 | {:ex_doc, "~> 0.23", only: :dev, runtime: false}, 33 | {:dialyxir, "~> 1.1", only: [:dev], runtime: false} 34 | ] 35 | end 36 | 37 | defp aliases do 38 | [ 39 | "assets.deploy": ["esbuild default --minify", "phx.digest"], 40 | setup: ["cmd mix setup"], 41 | "ecto.setup": ["ecto.drop", "ecto.create", "ecto.migrate"] 42 | ] 43 | end 44 | 45 | defp description() do 46 | "MishkaCms an open source and real time API base CMS Powered by Elixir and Phoenix" 47 | end 48 | 49 | defp package() do 50 | [ 51 | files: ~w(apps config .formatter.exs mix.exs LICENSE README*), 52 | licenses: ["Apache License 2.0"], 53 | maintainers: ["Shahryar Tavakkoli", "Mojtaba Naseri"], 54 | links: %{"GitHub" => "https://github.com/mishka-group/mishka-cms"} 55 | ] 56 | end 57 | end 58 | --------------------------------------------------------------------------------