├── .aidigestignore ├── .air.toml ├── .chat └── chat_log_lmquang_fortress-api_2025_05_28T04_21_36_071Z.md ├── .cursor └── rules │ └── mcp-playbook.mdc ├── .env.sample ├── .github └── workflows │ ├── build-tools.yaml │ ├── ci-test.yml │ ├── commitlint.yml │ ├── gke-dev.yml │ ├── gke-prod.yml │ └── golangci-lint.yaml ├── .gitignore ├── .golangci.yml ├── CODEOWNERS ├── Dockerfile ├── Makefile ├── README.md ├── cmd └── server │ └── main.go ├── dbconfig.yml ├── devbox.json ├── devbox.lock ├── docker-compose.yml ├── docs ├── adr │ ├── 0001-deal-closing-commission-and-soft-delete.md │ ├── 0002-adopt-email-syncing-for-notion-project-heads.md │ └── 0003-refactor-invoice-commission-db-access.md ├── changelog │ ├── 0001-deal-closing-commission.md │ ├── 0002-improved-project-head-syncing.md │ └── 0003-refactor-invoice-commission-logic.md ├── diagram │ └── payroll_commission_flow.md ├── docs.go ├── specs │ ├── 0001-deal-closing-commission-enhancements.md │ ├── 0002-notion-project-head-email-sync.md │ └── 0003-refactor-invoice-commission-logic-technical.md ├── swagger.json └── swagger.yaml ├── go.mod ├── go.sum ├── migrations ├── schemas │ ├── 20221102153827-init_employees_schema.sql │ ├── 20221104144115-init_user_permissions_schema.sql │ ├── 20221108214100-init_projects_schema.sql │ ├── 20221127165235-init_file_contents_schema.sql │ ├── 20221127165238-create_invoices_table.sql │ ├── 20221129122450-init_work_units_schema.sql │ ├── 20221205153244-init_feedbacks_schema.sql │ ├── 20221212015000-alter_table_add_missing_column.sql │ ├── 20221212015001-gen_username_data_for_employee.sql │ ├── 20221221053842-add_full_text_search_employees_table.sql │ ├── 20221227024809-alter_project_table.sql │ ├── 20221227042737-alter_employees_add_missing_column.sql │ ├── 20230103062027-add_employee_mentees_table.sql │ ├── 20230105032842-alter_projects_table.sql │ ├── 20230106033811-accounting.sql │ ├── 20230106033812-valuation.sql │ ├── 20230106075550-alter_table_add_missing_columns.sql │ ├── 20230109154551-init_audit_schema.sql │ ├── 20230117023858-alter_projects_table.sql │ ├── 20230118101417-alter_project_members_update_leftDate_joinedDate.sql │ ├── 20230130084819-add_organizations_table.sql │ ├── 20230201063507-init_social_accounts_table.sql │ ├── 20230206045042-alter_employees_table.sql │ ├── 20230207063521-alter_projects_table.sql │ ├── 20230208045042-icy_treasury.sql │ ├── 20230208143233-add_client_company_invoice_caching_table.sql │ ├── 20230208143342-add_project_notion_table.sql │ ├── 20230209143233-add_schedule.sql │ ├── 20230214122834-create_api_keys_table_and_auth_permissions.sql │ ├── 20230215021807-alter_projects_table.sql │ ├── 20230221215626-update_content_table.sql │ ├── 20230222033838-alter_project_slots_table.sql │ ├── 20230303090207-alter_audits_table.sql │ ├── 20230307184910-create_payroll_tables.sql │ ├── 20230313023453-alter_project_members_table.sql │ ├── 20230313023454-add_missing_updated_at_field.sql │ ├── 20230410074637-create_service_table.sql │ ├── 20230410074638-add-bank-info.sql │ ├── 20230417095551-create-expenses-table.sql │ ├── 20230419095551-create-audience-table.sql │ ├── 20230419095552-add_missing_updated_at_field_base_salary.sql │ ├── 20230419095553-change_invoice_number_data_type.sql │ ├── 20230419095554-add_employee_data_view.sql │ ├── 20230509095554-add_discord_log_template.sql │ ├── 20230512091353-drop-old-icy-txn.sql │ ├── 20230512091526-new-icy-txn.sql │ ├── 20230512110852-report-views.sql │ ├── 20230515162554-view-idle-employees.sql │ ├── 20230516000300-alter_employee_drop_not_null_team_email.sql │ ├── 20230516091724-alter_table_icy_tx_add_unique.sql │ ├── 20230517000301-add_table_employee_invitations.sql │ ├── 20230525000301-add_table_monthly_chapter_members_weekly_project_charge_rate.sql │ ├── 20230531143430-add_onleave_request_table.sql │ ├── 20230610100900-alter_roles_table_add_is_show_column.sql │ ├── 20230610112300-alter_projects_table_add_rating_important_cols.sql │ ├── 20230611051221-alter_icy_txn_table.sql │ ├── 20230613062354-engagements_rollup_init.sql │ ├── 20230619112538-add_brainery_reports_table.sql │ ├── 20230620172538-add_discord_accounts_table.sql │ ├── 20230622072538-add_coors_col_in_employees.sql │ ├── 20230630082538-remove_unused_columns_employees.sql │ ├── 20230701072225-add_column_clients.sql │ ├── 20230713033838-add_delivery_metric_logs_table.sql │ ├── 20230718143052-add-view-weekly-delivery-metrics.sql │ ├── 20230720050455-add-view-monthly-lelivery-metrics.sql │ ├── 20231005040551-add_employee_mma_scores_table.sql │ ├── 20231026123737-init-advance-salary-history.sql │ ├── 20231111011111-add_currency_conversion_rate.sql │ ├── 20231112134909-init-config.sql │ ├── 20231130215800-add-advance-salary-amount.sql │ ├── 20231130215800-change-advance-salary-amount-type.sql │ ├── 20231201075923-init_user_bank_account.sql │ ├── 20240318011415-add_invoice_bonus.sql │ ├── 20240322145850-remove_schedules_tabls.sql │ ├── 20240417112538-add_memo_logs_table.sql │ ├── 20240502144255-create_discord_events.sql │ ├── 20240513093025-extend_table_discount_accounts.sql │ ├── 20240513105259-add_table_memo_authors_and_unique_memo_link.sql │ ├── 20240513164949-remove_column_memo_logs_authors.sql │ ├── 20240627064435-add_memo_log_category.sql │ ├── 20240906073841-dropevent_speakers_event_id_discord_account_id_key.sql │ ├── 20240912134356-add_table_checkins.sql │ ├── 20240918064435-add_employee_bank_columns.sql │ ├── 20240918064436-add_table_physical_checkin_transactions.sql │ ├── 20240919023432-alter_table_checkins_update_id_type.sql │ ├── 20241025172810-view-project-salary-summary.sql │ ├── 20241030151941-view-project-cost-and-revenue.sql │ ├── 20241120044604-alter_table_employees_add_iskeepfwdemail.sql │ ├── 20241220064435-merge_memo_authors_to_memo_logs.sql │ ├── 20250122042534-alter_table_projects_add_project_artifact_link.sql │ ├── 20250123085334-add_source_doc_links_to_projects.sql │ ├── 20250524000000_add_inbound_fund_tracking.sql │ └── 20250525160000_add_deal_closing_to_project_head_positions_enum.sql ├── seed │ ├── accounting_categories.sql │ ├── banks.sql │ ├── chapters.sql │ ├── configs.sql │ ├── discord_log_templates.sql │ ├── employee_event_questions.sql │ ├── employee_event_reviewers.sql │ ├── employee_event_topics.sql │ ├── employee_mentees.sql │ ├── employee_organizations.sql │ ├── employee_positions.sql │ ├── employee_roles.sql │ ├── employee_stacks.sql │ ├── employees.sql │ ├── engagement_metrics.sql │ ├── feedback_events.sql │ ├── metadata.sql │ ├── permissions.sql │ ├── project_heads.sql │ ├── project_member_positions.sql │ ├── project_members.sql │ ├── project_slot_positions.sql │ ├── project_slots.sql │ ├── project_stacks.sql │ ├── projects.sql │ ├── role_permissions.sql │ ├── roles.sql │ ├── seed.sql │ ├── social_accounts.sql │ ├── work_unit_members.sql │ ├── work_unit_stacks.sql │ └── work_units.sql └── test_seed │ └── seed.sql ├── pkg ├── config │ ├── config.go │ ├── env_reader.go │ └── file_reader.go ├── constant │ └── constant.go ├── contracts │ ├── erc20 │ │ └── erc20.go │ ├── erc721 │ │ └── erc721.go │ └── icyswap │ │ └── icyswap.go ├── controller │ ├── auth │ │ ├── auth.go │ │ ├── create_apikey.go │ │ ├── errors.go │ │ ├── me.go │ │ └── new.go │ ├── brainerylogs │ │ ├── create.go │ │ ├── get_metrics.go │ │ └── new.go │ ├── client │ │ ├── create.go │ │ ├── delete.go │ │ ├── detail.go │ │ ├── errors.go │ │ ├── list.go │ │ ├── new.go │ │ └── update.go │ ├── communitynft │ │ ├── errors.go │ │ ├── metadata.go │ │ └── new.go │ ├── companyinfo │ │ ├── list.go │ │ └── new.go │ ├── controller.go │ ├── conversionrate │ │ ├── errors.go │ │ ├── new.go │ │ └── sync.go │ ├── deliverymetrics │ │ ├── get.go │ │ ├── leaderboard.go │ │ ├── new.go │ │ └── sync.go │ ├── discord │ │ └── new.go │ ├── dynamicevents │ │ ├── dynamic_events.go │ │ ├── events.go │ │ └── interface.go │ ├── earn │ │ ├── earn.go │ │ ├── interface.go │ │ └── new.go │ ├── employee │ │ ├── checkin.go │ │ ├── create.go │ │ ├── details.go │ │ ├── earns.go │ │ ├── errors.go │ │ ├── get_line_managers.go │ │ ├── list.go │ │ ├── new.go │ │ ├── salary_advance.go │ │ ├── update_base_salary.go │ │ ├── update_employee_status.go │ │ ├── update_general_info.go │ │ ├── update_personal_info.go │ │ ├── update_role.go │ │ ├── update_skills.go │ │ └── upload_avatar.go │ ├── event │ │ └── event.go │ ├── icy │ │ └── icy.go │ ├── invoice │ │ ├── commission.go │ │ ├── errors.go │ │ ├── get_template.go │ │ ├── list.go │ │ ├── new.go │ │ ├── send.go │ │ └── update_status.go │ ├── memologs │ │ ├── new.go │ │ ├── pr.go │ │ ├── sweep.go │ │ └── sync.go │ └── news │ │ ├── interface.go │ │ ├── lobsters.go │ │ ├── new.go │ │ └── reddit.go ├── handler │ ├── accounting │ │ ├── accounting.go │ │ └── service.go │ ├── asset │ │ ├── asset.go │ │ ├── errs │ │ │ └── errors.go │ │ └── interface.go │ ├── audit │ │ ├── audit.go │ │ ├── errs │ │ │ └── errors.go │ │ └── interface.go │ ├── auth │ │ ├── auth.go │ │ ├── auth.png │ │ ├── errs │ │ │ └── errors.go │ │ ├── interface.go │ │ └── request │ │ │ └── request.go │ ├── bankaccount │ │ ├── bank_account.go │ │ ├── bank_account_test.go │ │ ├── interface.go │ │ └── testdata │ │ │ └── list │ │ │ ├── 200.json │ │ │ └── list.sql │ ├── brainerylogs │ │ ├── brainery_log.go │ │ ├── errs │ │ │ └── errors.go │ │ ├── interface.go │ │ └── request │ │ │ └── request.go │ ├── client │ │ ├── client.go │ │ ├── errs │ │ │ └── errors.go │ │ ├── interface.go │ │ ├── request │ │ │ └── request.go │ │ └── testdata │ │ │ ├── create │ │ │ └── create.sql │ │ │ ├── delete │ │ │ ├── 200.json │ │ │ ├── 404.json │ │ │ └── delete.sql │ │ │ ├── detail │ │ │ ├── 200.json │ │ │ ├── 404.json │ │ │ └── detail.sql │ │ │ ├── list │ │ │ ├── 200.json │ │ │ └── list.sql │ │ │ └── update_client │ │ │ ├── 200.json │ │ │ ├── 404.json │ │ │ └── update_client.sql │ ├── communitynft │ │ ├── communitynft.go │ │ ├── errs │ │ │ └── errors.go │ │ └── interface.go │ ├── companyinfo │ │ ├── company_info.go │ │ └── interface.go │ ├── conversionrate │ │ ├── conversion_rate.go │ │ └── interface.go │ ├── dashboard │ │ ├── dashboard.go │ │ ├── dashboard_test.go │ │ ├── errs │ │ │ └── errors.go │ │ ├── interface.go │ │ ├── request │ │ │ └── request.go │ │ ├── testdata │ │ │ ├── action_item_squash │ │ │ │ ├── 200.json │ │ │ │ ├── 200_with_project_id.json │ │ │ │ ├── action_items.sql │ │ │ │ └── project_not_found.json │ │ │ ├── action_items │ │ │ │ ├── 200.json │ │ │ │ ├── 200_with_project_id.json │ │ │ │ └── action_items.sql │ │ │ ├── audits │ │ │ │ ├── 200_with_project_id.json │ │ │ │ ├── 200_without_project_id.json │ │ │ │ └── audits.sql │ │ │ ├── engagement_info │ │ │ │ ├── 200.json │ │ │ │ ├── happy_case.sql │ │ │ │ └── no_record.json │ │ │ ├── engagement_info_detail │ │ │ │ ├── 200.json │ │ │ │ ├── happy_case.sql │ │ │ │ ├── invalid_filter.json │ │ │ │ └── invalid_start_date.json │ │ │ ├── engineering_healths │ │ │ │ ├── 200_with_project_id.json │ │ │ │ ├── 200_without_project_id.json │ │ │ │ └── engineering_healths.sql │ │ │ ├── get_resource_utilization │ │ │ │ ├── 200_ok.json │ │ │ │ └── seed.sql │ │ │ ├── get_resource_work_survey_summaries │ │ │ │ ├── 200.json │ │ │ │ ├── 200_with_keyword.json │ │ │ │ └── seed.sql │ │ │ ├── get_resources_availability │ │ │ │ ├── 200.json │ │ │ │ └── seed.sql │ │ │ ├── project_sizes │ │ │ │ ├── 200.json │ │ │ │ └── project_sizes.sql │ │ │ ├── summary │ │ │ │ ├── 200.json │ │ │ │ └── summary.sql │ │ │ ├── work_surveys │ │ │ │ ├── 200.json │ │ │ │ ├── 200_with_project_id.json │ │ │ │ └── work_surveys.sql │ │ │ ├── work_unit_distribution │ │ │ │ ├── 200_with_name.json │ │ │ │ ├── 200_with_name_and_sort.json │ │ │ │ ├── 200_with_name_sort_and_type.json │ │ │ │ ├── 400_invalid_sort.json │ │ │ │ ├── 400_invalid_type.json │ │ │ │ └── work_unit_distribution.sql │ │ │ └── work_unit_distribution_summary │ │ │ │ ├── 200.json │ │ │ │ └── work_unit_distribution_summary.sql │ │ └── util │ │ │ ├── interface.go │ │ │ ├── mocks │ │ │ └── util.go │ │ │ └── util.go │ ├── deliverymetric │ │ ├── discord_msg.go │ │ ├── get.go │ │ ├── interface.go │ │ ├── new.go │ │ └── sync.go │ ├── discord │ │ ├── discord.go │ │ ├── errs │ │ │ └── errors.go │ │ ├── interface.go │ │ └── request │ │ │ ├── request.go │ │ │ └── top_memo_authors.go │ ├── dynamicevents │ │ ├── dynamic_events.go │ │ ├── events.go │ │ ├── interface.go │ │ └── request │ │ │ └── request.go │ ├── earn │ │ ├── earn.go │ │ └── interface.go │ ├── employee │ │ ├── employee.go │ │ ├── employee_test.go │ │ ├── errs │ │ │ └── errors.go │ │ ├── interface.go │ │ ├── request │ │ │ └── request.go │ │ └── testdata │ │ │ ├── create │ │ │ ├── create.sql │ │ │ ├── existed_user.json │ │ │ ├── invalid_uuid.json │ │ │ └── validation_err.json │ │ │ ├── get_line_managers │ │ │ ├── 200_ok.json │ │ │ └── seed.sql │ │ │ ├── list │ │ │ ├── have_working_and_no_pagination.json │ │ │ ├── have_working_and_pagination.json │ │ │ ├── invalid_chapter_code.json │ │ │ ├── invalid_organization_code.json │ │ │ ├── invalid_position_code.json │ │ │ ├── invalid_project_code.json │ │ │ ├── invalid_seniority_code.json │ │ │ ├── invalid_stack_code.json │ │ │ ├── list.sql │ │ │ ├── out_of_content.json │ │ │ ├── with_keyword.json │ │ │ ├── with_list_working_status.json │ │ │ ├── with_multiple_stack.json │ │ │ ├── with_preload_false.json │ │ │ ├── with_project_code_and_position_code.json │ │ │ ├── with_stack_code.json │ │ │ ├── without_preload.json │ │ │ └── without_working_status_and_pagination.json │ │ │ ├── one │ │ │ ├── 200.json │ │ │ ├── 404.json │ │ │ └── one.sql │ │ │ ├── update_employee_status │ │ │ ├── 200.json │ │ │ ├── 400.json │ │ │ ├── 404.json │ │ │ ├── invalid_employee_status.json │ │ │ └── update_employee_status.sql │ │ │ ├── update_general_info │ │ │ ├── 200.json │ │ │ ├── 400.json │ │ │ ├── 404.json │ │ │ ├── invalid_join_date.json │ │ │ ├── line_manager_not_found.json │ │ │ ├── organization_not_found.json │ │ │ └── update_general_info.sql │ │ │ ├── update_personal_info │ │ │ ├── 200.json │ │ │ ├── 400.json │ │ │ ├── 404.json │ │ │ ├── invalid_country.json │ │ │ └── update_personal_info.sql │ │ │ ├── update_role │ │ │ ├── 200.json │ │ │ ├── 404.json │ │ │ ├── 404_role.json │ │ │ └── update_role.sql │ │ │ └── update_skills │ │ │ ├── 200.json │ │ │ ├── 400.json │ │ │ ├── 404.json │ │ │ ├── stack_not_found.json │ │ │ └── update_skills.sql │ ├── engagement │ │ ├── engagement.go │ │ ├── errors.go │ │ ├── interface.go │ │ └── request │ │ │ └── request.go │ ├── feedback │ │ ├── errs │ │ │ └── errors.go │ │ ├── feedback.go │ │ ├── feedback_test.go │ │ ├── interface.go │ │ ├── request │ │ │ └── request.go │ │ └── testdata │ │ │ ├── detail │ │ │ ├── 200.json │ │ │ ├── 200_engagement.json │ │ │ ├── 200_work.json │ │ │ ├── 404.json │ │ │ └── detail.sql │ │ │ ├── get_unread_inbox │ │ │ ├── 200_happy_case.json │ │ │ └── get_unread_inbox.sql │ │ │ ├── list │ │ │ ├── 200_empty_query.json │ │ │ ├── 200_get_draft_feedbacks.json │ │ │ ├── invalid_status.json │ │ │ └── list.sql │ │ │ └── submit │ │ │ ├── 200.json │ │ │ ├── 200_engagement.json │ │ │ ├── 200_work.json │ │ │ ├── 400_unanswer_question.json │ │ │ ├── 404.json │ │ │ └── submit.sql │ ├── handler.go │ ├── healthz │ │ ├── healthz.go │ │ └── interface.go │ ├── icy │ │ ├── icy.go │ │ └── interface.go │ ├── invoice │ │ ├── errs │ │ │ └── errors.go │ │ ├── interface.go │ │ ├── invoice.go │ │ ├── request │ │ │ └── request.go │ │ └── testdata │ │ │ ├── create │ │ │ ├── 200.json │ │ │ ├── 400.json │ │ │ ├── 404.json │ │ │ └── create.sql │ │ │ ├── get_latest │ │ │ ├── 200.json │ │ │ └── get_latest.sql │ │ │ └── update_status │ │ │ ├── 200.json │ │ │ ├── 400_invalid_status.json │ │ │ ├── 404.json │ │ │ └── update_status.sql │ ├── memologs │ │ ├── errs │ │ │ └── errors.go │ │ ├── interface.go │ │ ├── memo_log.go │ │ └── request │ │ │ └── request.go │ ├── metadata │ │ ├── errors.go │ │ ├── errs │ │ │ └── errs.go │ │ ├── interface.go │ │ ├── metadata.go │ │ ├── metadata_test.go │ │ ├── request.go │ │ ├── request │ │ │ └── request.go │ │ └── testdata │ │ │ ├── create_position │ │ │ └── 200.json │ │ │ ├── create_stack │ │ │ └── 200.json │ │ │ ├── delete_position │ │ │ └── 200.json │ │ │ ├── delete_stack │ │ │ └── 200.json │ │ │ ├── get_account_roles │ │ │ └── 200.json │ │ │ ├── get_chapters │ │ │ └── 200.json │ │ │ ├── get_positions │ │ │ └── 200.json │ │ │ ├── get_project_statuses │ │ │ └── 200.json │ │ │ ├── get_questions │ │ │ ├── 200.json │ │ │ └── 400.json │ │ │ ├── get_seniorities │ │ │ └── 200.json │ │ │ ├── get_stacks │ │ │ └── 200.json │ │ │ ├── get_working_status │ │ │ └── 200.json │ │ │ ├── update_position │ │ │ ├── 200.json │ │ │ └── 404.json │ │ │ └── update_stack │ │ │ ├── 200.json │ │ │ └── 404.json │ ├── news │ │ ├── fetch.go │ │ ├── interface.go │ │ └── news.go │ ├── notion │ │ ├── audience.go │ │ ├── changelog.go │ │ ├── digest.go │ │ ├── earn.go │ │ ├── event.go │ │ ├── hiring.go │ │ ├── interface.go │ │ ├── issue.go │ │ ├── memo.go │ │ ├── newsletter.go │ │ ├── project_milestone.go │ │ ├── staffing_demand.go │ │ ├── tech_radar.go │ │ └── update.go │ ├── payroll │ │ ├── bhxh.go │ │ ├── commit.go │ │ ├── details.go │ │ ├── errs │ │ │ └── errors.go │ │ ├── mark_paid.go │ │ ├── new.go │ │ ├── payroll_calculator.go │ │ └── types.go │ ├── profile │ │ ├── errs │ │ │ └── errors.go │ │ ├── interface.go │ │ ├── profile.go │ │ ├── profile_test.go │ │ ├── request │ │ │ └── request.go │ │ └── testdata │ │ │ ├── get_profile │ │ │ ├── 200.json │ │ │ └── get_profile.sql │ │ │ └── update_info │ │ │ ├── 200.json │ │ │ ├── 400.json │ │ │ └── update_info.sql │ ├── project │ │ ├── errs │ │ │ └── errors.go │ │ ├── interface.go │ │ ├── project.go │ │ ├── project_test.go │ │ ├── request │ │ │ └── request.go │ │ └── testdata │ │ │ ├── archive_work_unit │ │ │ ├── 200_ok.json │ │ │ ├── 404_project_not_found.json │ │ │ ├── archive_work_unit.sql │ │ │ ├── invalid_project_id.json │ │ │ └── invalid_work_unit_id.json │ │ │ ├── assign_member │ │ │ ├── 200_success.json │ │ │ ├── 404_project_not_found.json │ │ │ ├── assign_member.sql │ │ │ └── invalid_project_id.json │ │ │ ├── create │ │ │ ├── 200.json │ │ │ ├── 200_with_members.json │ │ │ ├── 400_duplicate_slug.json │ │ │ ├── 400_invalid_deployment_type.json │ │ │ ├── 400_invalid_email.json │ │ │ ├── 400_invalid_end_date_member.json │ │ │ ├── 400_invalid_function.json │ │ │ ├── 400_invalid_startDate.json │ │ │ ├── 400_invalid_start_date_member.json │ │ │ ├── 400_invalid_status.json │ │ │ ├── 400_invalid_type.json │ │ │ ├── 400_missing_account_manager.json │ │ │ ├── 400_misssing_name.json │ │ │ ├── 400_misssing_status.json │ │ │ ├── 400_project_member_status.json │ │ │ ├── 400_project_position_empty.json │ │ │ └── create.sql │ │ │ ├── create_work_unit │ │ │ ├── 200_success.json │ │ │ ├── 404_project_not_found.json │ │ │ ├── create_work_unit.sql │ │ │ ├── invalid_project_id.json │ │ │ ├── invalid_work_unit_stack.json │ │ │ ├── invalid_work_unit_status.json │ │ │ └── invalid_work_unit_type.json │ │ │ ├── delete_member │ │ │ ├── 200.json │ │ │ ├── 404.json │ │ │ ├── delete_member.sql │ │ │ ├── empty_member_id.json │ │ │ ├── empty_project_id.json │ │ │ └── project_not_found.json │ │ │ ├── delete_slot │ │ │ ├── 200.json │ │ │ ├── 404.json │ │ │ ├── delete_slot.sql │ │ │ ├── empty_project_id.json │ │ │ ├── empty_slot_id.json │ │ │ └── project_not_found.json │ │ │ ├── get_list_work_unit │ │ │ ├── 200.json │ │ │ ├── 400.json │ │ │ ├── 404.json │ │ │ ├── get_list_work_unit.sql │ │ │ └── invalid_project_id.json │ │ │ ├── get_members │ │ │ ├── 200.json │ │ │ ├── distinct.json │ │ │ ├── get_members.sql │ │ │ ├── invalid_project_id.json │ │ │ ├── invalid_project_member_status.json │ │ │ ├── project_not_found.json │ │ │ └── without_preload.json │ │ │ ├── get_project │ │ │ ├── 200.json │ │ │ ├── 404.json │ │ │ ├── get_project.sql │ │ │ └── invalid_project_id.json │ │ │ ├── get_projects │ │ │ ├── 200.json │ │ │ ├── 200_with_paging.json │ │ │ ├── get_projects.sql │ │ │ ├── invalid_project_status.json │ │ │ └── invalid_project_type.json │ │ │ ├── unarchive_work_unit │ │ │ ├── 200_ok.json │ │ │ ├── 404_project_not_found.json │ │ │ ├── invalid_project_id.json │ │ │ ├── invalid_work_unit_id.json │ │ │ └── unarchive_work_unit.sql │ │ │ ├── unassign_member │ │ │ ├── 200.json │ │ │ ├── 404.json │ │ │ ├── empty_member_id.json │ │ │ ├── empty_project_id.json │ │ │ ├── project_not_found.json │ │ │ └── unassign_member.sql │ │ │ ├── update_contact_info │ │ │ ├── 200.json │ │ │ ├── 404.json │ │ │ ├── account_manager_not_found.json │ │ │ ├── delivery_manager_not_found.json │ │ │ ├── invalid_email_format.json │ │ │ ├── invalid_project_id.json │ │ │ └── update_contact_info.sql │ │ │ ├── update_general_info │ │ │ ├── 200.json │ │ │ ├── 404.json │ │ │ ├── country_not_found.json │ │ │ ├── invalid_project_function.json │ │ │ ├── invalid_project_id.json │ │ │ ├── stack_not_found.json │ │ │ └── update_general_info.sql │ │ │ ├── update_member │ │ │ ├── 200_success.json │ │ │ ├── 400_invalid_start_date.json │ │ │ ├── 404_project_not_found.json │ │ │ ├── invalid_deployment_type.json │ │ │ ├── invalid_project_id.json │ │ │ ├── invalid_status.json │ │ │ ├── position_not_found.json │ │ │ ├── project_slot_not_found.json │ │ │ ├── seniority_not_found.json │ │ │ └── update_member.sql │ │ │ ├── update_project_status │ │ │ ├── 200.json │ │ │ ├── 400.json │ │ │ ├── 404.json │ │ │ ├── invalid_project_id.json │ │ │ └── update_project_status.sql │ │ │ ├── update_sending_survey │ │ │ ├── 200.json │ │ │ ├── 404.json │ │ │ ├── invalid_project_id.json │ │ │ └── update_sending_survey.sql │ │ │ └── update_work_unit │ │ │ ├── 200.json │ │ │ ├── 400.json │ │ │ ├── 404.json │ │ │ ├── invalid_project_id.json │ │ │ ├── invalid_stack.json │ │ │ ├── stack_not_found.json │ │ │ └── update_work_unit.sql │ ├── survey │ │ ├── errs │ │ │ └── errors.go │ │ ├── interface.go │ │ ├── request │ │ │ └── request.go │ │ ├── survey.go │ │ ├── survey_test.go │ │ └── testdata │ │ │ ├── create_survey │ │ │ ├── 200_work.json │ │ │ ├── 400.json │ │ │ ├── create_survey.sql │ │ │ ├── invalid_date.json │ │ │ └── invalid_subtype.json │ │ │ ├── delete_survey │ │ │ ├── 200_valid_id.json │ │ │ ├── 404_event_not_found.json │ │ │ ├── delete_survey.sql │ │ │ ├── invalid_event_id.json │ │ │ ├── invalid_topic_id.json │ │ │ └── topic_not_found.json │ │ │ ├── delete_topic_participants │ │ │ ├── 200.json │ │ │ ├── 404.json │ │ │ └── delete_topic_participants.sql │ │ │ ├── get_peer_review_detail │ │ │ ├── 200.json │ │ │ ├── 404.json │ │ │ ├── get_peer_review_detail.sql │ │ │ ├── invalid_feedback_id.json │ │ │ ├── invalid_topic_id.json │ │ │ └── topic_not_found.json │ │ │ ├── get_survey_detail │ │ │ ├── 200_engagement.json │ │ │ ├── 200_happy_case.json │ │ │ ├── 200_work.json │ │ │ ├── 404_event_id_not_found.json │ │ │ ├── get_survey_detail.sql │ │ │ └── invalid_event_id.json │ │ │ ├── get_survey_review_detail │ │ │ ├── 200_happy_case.json │ │ │ ├── 200_work.json │ │ │ ├── 404_not_found.json │ │ │ ├── get_survey_review_detail.sql │ │ │ ├── invalid_event_id.json │ │ │ ├── invalid_review_id.json │ │ │ └── invalid_topic_id.json │ │ │ ├── list_survey │ │ │ ├── 200_get_peer_review.json │ │ │ ├── 400_empty_query.json │ │ │ └── list_survey.sql │ │ │ ├── mark_done │ │ │ ├── 200.json │ │ │ ├── 400.json │ │ │ ├── 404.json │ │ │ ├── invalid_event_id.json │ │ │ └── mark_done.sql │ │ │ ├── send_survey │ │ │ ├── 200_performance_review.json │ │ │ ├── 200_send_engagement.json │ │ │ ├── 404.json │ │ │ ├── invalid_event_id.json │ │ │ ├── invalid_subtype.json │ │ │ └── send_survey.sql │ │ │ └── update_topic_participants │ │ │ ├── 200_happy_case.json │ │ │ ├── 400_participant_not_ready.json │ │ │ ├── invalid_event_id.json │ │ │ ├── invalid_topic_id.json │ │ │ └── update_topic_participants.sql │ ├── valuation │ │ ├── interface.go │ │ └── valuation.go │ ├── vault │ │ ├── interface.go │ │ └── vault.go │ ├── webhook │ │ ├── basecamp.go │ │ ├── basecamp_accounting.go │ │ ├── basecamp_expense.go │ │ ├── basecamp_invoice.go │ │ ├── constant.go │ │ ├── interface.go │ │ ├── n8n.go │ │ ├── onleave.go │ │ ├── request.go │ │ └── webhook.go │ └── youtube │ │ ├── file.go │ │ ├── interface.go │ │ └── youtube.go ├── logger │ ├── logger.go │ └── logrus.go ├── model │ ├── accounting.go │ ├── action_item_snapshot.go │ ├── action_items.go │ ├── answer.go │ ├── answer_drafts.go │ ├── api_key.go │ ├── api_key_roles.go │ ├── asset.go │ ├── audit_action_item.go │ ├── audit_cycles.go │ ├── audit_item.go │ ├── audit_participants.go │ ├── audits.go │ ├── auth.go │ ├── bank_account.go │ ├── banks.go │ ├── base.go │ ├── base_salary.go │ ├── basecamp.go │ ├── brainery_log.go │ ├── cached_payroll.go │ ├── candidate.go │ ├── chapters.go │ ├── client.go │ ├── client_contact.go │ ├── commission.go │ ├── communitynft.go │ ├── company_info.go │ ├── config.go │ ├── content.go │ ├── conversion_rate.go │ ├── country.go │ ├── currency.go │ ├── dashboard.go │ ├── date_time.go │ ├── delivery_metric.go │ ├── discord.go │ ├── discord_account.go │ ├── discord_message.go │ ├── dynamic_events.go │ ├── earn.go │ ├── email.go │ ├── employee_bonus.go │ ├── employee_chapters.go │ ├── employee_commissions.go │ ├── employee_earns.go │ ├── employee_event_questions.go │ ├── employee_event_reviewer.go │ ├── employee_event_topic.go │ ├── employee_invitations.go │ ├── employee_mentees.go │ ├── employee_mma_score.go │ ├── employee_organizations.go │ ├── employee_positions.go │ ├── employee_roles.go │ ├── employee_salary.go │ ├── employee_stacks.go │ ├── employees.go │ ├── engagement_rollup.go │ ├── event.go │ ├── expense.go │ ├── feedback_events.go │ ├── google_mail.go │ ├── icy.go │ ├── icy_distribution.go │ ├── icy_transaction.go │ ├── inbound_fund_transaction.go │ ├── invoice.go │ ├── invoice_number_caching.go │ ├── json.go │ ├── liability.go │ ├── memo_author.go │ ├── memo_log.go │ ├── memopr.go │ ├── mochi.go │ ├── monthly_delivery_metric.go │ ├── news.go │ ├── notion.go │ ├── notion_event.go │ ├── onleave_request.go │ ├── operational_service.go │ ├── organization.go │ ├── pagination.go │ ├── pagination_test.go │ ├── payroll.go │ ├── permissions.go │ ├── physical_checkin_transactions.go │ ├── positions.go │ ├── project_commission_configs.go │ ├── project_info.go │ ├── project_issue.go │ ├── project_member_positions.go │ ├── project_notion.go │ ├── project_slot_positions.go │ ├── projects.go │ ├── questions.go │ ├── research_topic.go │ ├── roles.go │ ├── salary_advance.go │ ├── schedule.go │ ├── senitorities.go │ ├── social_account.go │ ├── stacks.go │ ├── transferwise.go │ ├── user_bank_accounts.go │ ├── uuid.go │ ├── uuid_test.go │ ├── valuation.go │ ├── webhook.go │ ├── weekly_delivery_metric.go │ ├── wise.go │ ├── work_unit_members.go │ ├── work_unit_stacks.go │ ├── work_units.go │ └── worker_message.go ├── mw │ ├── errors.go │ ├── mw.go │ └── mw_test.go ├── request │ └── validator.go ├── routes │ ├── routes.go │ ├── v1.go │ └── v1_test.go ├── service │ ├── basecamp │ │ ├── attachment │ │ │ ├── attachment.go │ │ │ └── service.go │ │ ├── basecamp.go │ │ ├── campfire │ │ │ ├── campfire.go │ │ │ └── service.go │ │ ├── client │ │ │ ├── client.go │ │ │ └── service.go │ │ ├── comment │ │ │ ├── comment.go │ │ │ └── service.go │ │ ├── consts │ │ │ └── consts.go │ │ ├── integration.go │ │ ├── messageboard │ │ │ ├── message_board.go │ │ │ └── service.go │ │ ├── model │ │ │ └── model.go │ │ ├── people │ │ │ ├── people.go │ │ │ └── service.go │ │ ├── project │ │ │ ├── project.go │ │ │ └── service.go │ │ ├── recording │ │ │ ├── recording.go │ │ │ └── service.go │ │ ├── schedule │ │ │ ├── schedule.go │ │ │ └── service.go │ │ ├── subscription │ │ │ ├── service.go │ │ │ └── subscription.go │ │ ├── todo │ │ │ ├── service.go │ │ │ └── todo.go │ │ └── webhook │ │ │ ├── service.go │ │ │ └── webhook.go │ ├── communitynft │ │ └── communitynft.go │ ├── currency │ │ ├── currency.go │ │ └── interface.go │ ├── discord │ │ ├── const.go │ │ ├── discord.go │ │ ├── service.go │ │ └── utils.go │ ├── evm │ │ ├── evm.go │ │ └── model.go │ ├── git │ │ ├── git.go │ │ └── inteface.go │ ├── github │ │ ├── errors.go │ │ ├── github.go │ │ └── service.go │ ├── google │ │ ├── google.go │ │ └── interface.go │ ├── googleadmin │ │ ├── google_admin.go │ │ └── interface.go │ ├── googledrive │ │ ├── google_drive.go │ │ └── interface.go │ ├── googlemail │ │ ├── google_mail.go │ │ ├── interface.go │ │ └── utils.go │ ├── googlesheet │ │ ├── google_sheet.go │ │ ├── interface.go │ │ └── types.go │ ├── googlestorage │ │ ├── gcs.go │ │ ├── google.go │ │ └── interface.go │ ├── icyswap │ │ └── icyswap.go │ ├── improvmx │ │ ├── improvmx.go │ │ └── service.go │ ├── landingzone │ │ ├── gcs.go │ │ ├── google.go │ │ └── interface.go │ ├── lobsters │ │ ├── interface.go │ │ ├── new.go │ │ └── news.go │ ├── mochi │ │ ├── mochi.go │ │ ├── model.go │ │ ├── request.go │ │ └── response.go │ ├── mochipay │ │ ├── mochipay.go │ │ └── request.go │ ├── mochiprofile │ │ ├── mochiprofile.go │ │ └── request.go │ ├── notion │ │ ├── interface.go │ │ ├── notion.go │ │ └── template.go │ ├── ogifmemosummarizer │ │ ├── dify.go │ │ └── interface.go │ ├── reddit │ │ ├── fetch_go_news.go │ │ ├── interface.go │ │ └── new.go │ ├── sendgrid │ │ └── sendgrid.go │ ├── service.go │ ├── tono │ │ ├── request.go │ │ └── tono.go │ ├── vault │ │ ├── interface.go │ │ └── vault.go │ ├── wise │ │ ├── interface.go │ │ └── wise.go │ └── youtube │ │ ├── interface.go │ │ └── youtube.go ├── store │ ├── accounting │ │ ├── accounting.go │ │ └── interface.go │ ├── actionitem │ │ ├── action_item.go │ │ └── interface.go │ ├── actionitemsnapshot │ │ ├── action_item_snapshot.go │ │ └── interface.go │ ├── apikey │ │ ├── api_key.go │ │ └── interface.go │ ├── apikeyrole │ │ ├── api_key_role.go │ │ └── interface.go │ ├── audit │ │ ├── audit.go │ │ └── interface.go │ ├── auditactionitem │ │ ├── audit_action_item.go │ │ └── interface.go │ ├── auditcycle │ │ ├── audit_cycle.go │ │ └── interface.go │ ├── audititem │ │ ├── audit_item.go │ │ └── interface.go │ ├── auditparticipant │ │ ├── audit_participant.go │ │ └── interface.go │ ├── bank │ │ ├── bank.go │ │ └── interface.go │ ├── bankaccount │ │ ├── bank_account.go │ │ └── interface.go │ ├── basesalary │ │ ├── base_salary.go │ │ └── interface.go │ ├── brainerylog │ │ ├── brainery_log.go │ │ └── interface.go │ ├── cachedpayroll │ │ ├── cached_payroll.go │ │ └── interface.go │ ├── chapter │ │ ├── chapter.go │ │ └── interface.go │ ├── client │ │ ├── client.go │ │ └── interface.go │ ├── clientcontact │ │ ├── clientcontact.go │ │ └── interface.go │ ├── companyinfo │ │ ├── companyinfo.go │ │ └── interface.go │ ├── config │ │ ├── config.go │ │ └── interface.go │ ├── content │ │ ├── content.go │ │ └── interface.go │ ├── conversionrate │ │ ├── conversion_rate.go │ │ └── interface.go │ ├── country │ │ ├── country.go │ │ └── interface.go │ ├── currency │ │ ├── currency.go │ │ └── interface.go │ ├── dashboard │ │ ├── dashboard.go │ │ └── interface.go │ ├── deliverymetric │ │ ├── delivery_metric.go │ │ └── interface.go │ ├── deliverymetricmonthly │ │ ├── get.go │ │ └── interface.go │ ├── deliverymetricweekly │ │ ├── get.go │ │ └── interface.go │ ├── discordaccount │ │ ├── discord_account.go │ │ └── interface.go │ ├── discordevent │ │ ├── discord_event.go │ │ └── interface.go │ ├── discordtemplate │ │ ├── discord_template.go │ │ └── interface.go │ ├── employee │ │ ├── employee.go │ │ ├── interface.go │ │ ├── request.go │ │ └── util.go │ ├── employeebonus │ │ ├── employee_bonus.go │ │ └── interface.go │ ├── employeechapter │ │ ├── employee_chapter.go │ │ └── interface.go │ ├── employeecommission │ │ ├── employee_commission.go │ │ ├── employee_commission_test.go │ │ └── interface.go │ ├── employeeeventquestion │ │ ├── employee_event_question.go │ │ ├── interface.go │ │ └── request.go │ ├── employeeeventreviewer │ │ ├── employee_event_reviewer.go │ │ └── interface.go │ ├── employeeeventtopic │ │ ├── employee_event_topic.go │ │ ├── interface.go │ │ └── request.go │ ├── employeeinvitation │ │ ├── employee_invitation.go │ │ └── interface.go │ ├── employeeorganization │ │ ├── employee_organization.go │ │ └── interface.go │ ├── employeeposition │ │ ├── employee_position.go │ │ └── interface.go │ ├── employeerole │ │ ├── employee_role.go │ │ └── interface.go │ ├── employeestack │ │ ├── employee_stack.go │ │ └── interface.go │ ├── engagementsrollup │ │ ├── engagements_rollup.go │ │ └── interface.go │ ├── eventspeaker │ │ ├── event_speaker.go │ │ └── interface.go │ ├── expense │ │ ├── expense.go │ │ └── interface.go │ ├── feedbackevent │ │ ├── feedback_event.go │ │ └── interface.go │ ├── icydistribution │ │ ├── icy_distribution.go │ │ └── interface.go │ ├── icytransaction │ │ ├── icy_transaction.go │ │ └── interface.go │ ├── inboundfundtransaction │ │ ├── inbound_fund_transaction.go │ │ ├── interface.go │ │ └── query.go │ ├── invoice │ │ ├── interface.go │ │ └── invoice.go │ ├── invoicenumbercaching │ │ ├── interface.go │ │ └── invoice_number_caching.go │ ├── memolog │ │ ├── interface.go │ │ └── memo_log.go │ ├── onleaverequest │ │ ├── interface.go │ │ └── onleave_request.go │ ├── operationalservice │ │ ├── interface.go │ │ └── operational_service.go │ ├── organization │ │ ├── interface.go │ │ └── organization.go │ ├── payroll │ │ ├── input.go │ │ ├── interface.go │ │ ├── payroll.go │ │ └── payroll_test.go │ ├── permission │ │ ├── interface.go │ │ └── permission.go │ ├── physicalcheckin │ │ ├── interface.go │ │ └── physical_checkin.go │ ├── position │ │ ├── interface.go │ │ └── position.go │ ├── project │ │ ├── interface.go │ │ ├── project.go │ │ └── request.go │ ├── projectcommissionconfig │ │ ├── interface.go │ │ └── project_commission_config.go │ ├── projecthead │ │ ├── interface.go │ │ └── project_head.go │ ├── projectmember │ │ ├── interface.go │ │ └── project_member.go │ ├── projectmemberposition │ │ ├── interface.go │ │ └── project_member_position.go │ ├── projectnotion │ │ ├── interface.go │ │ └── project_notion.go │ ├── projectslot │ │ ├── interface.go │ │ └── project_slot.go │ ├── projectslotposition │ │ ├── interface.go │ │ └── project_slot_position.go │ ├── projectstack │ │ ├── interface.go │ │ └── project_stack.go │ ├── question │ │ ├── interface.go │ │ └── question.go │ ├── recruitment │ │ ├── interface.go │ │ └── recruitment.go │ ├── repo.go │ ├── role │ │ ├── interface.go │ │ └── role.go │ ├── salaryadvance │ │ ├── interface.go │ │ └── salary_advance.go │ ├── schedule │ │ ├── interface.go │ │ └── schedule.go │ ├── seniority │ │ ├── interface.go │ │ └── seniority.go │ ├── socialaccount │ │ ├── interface.go │ │ └── social_account.go │ ├── stack │ │ ├── interface.go │ │ └── stack.go │ ├── store.go │ ├── store_util.go │ ├── test_repo.go │ ├── valuation │ │ ├── interface.go │ │ └── valuation.go │ ├── workunit │ │ ├── interface.go │ │ └── work_unit.go │ ├── workunitmember │ │ ├── interface.go │ │ └── work_unit_member.go │ └── workunitstack │ │ ├── interface.go │ │ └── work_unit_stack.go ├── templates │ ├── assets │ │ └── fonts │ │ │ ├── AvenirNext-Bold.woff │ │ │ ├── AvenirNext-BoldItalic.woff │ │ │ ├── AvenirNext-DemiBold.eot │ │ │ ├── AvenirNext-DemiBold.svg │ │ │ ├── AvenirNext-DemiBold.woff │ │ │ ├── AvenirNext-DemiBoldItalic.woff │ │ │ ├── AvenirNext-Heavy.woff │ │ │ ├── AvenirNext-HeavyItalic.woff │ │ │ ├── AvenirNext-Italic.woff │ │ │ ├── AvenirNext-Medium.woff │ │ │ ├── AvenirNext-MediumItalic.woff │ │ │ └── AvenirNext-Regular.woff │ ├── candidate_inform.tpl │ ├── community_nft.tpl │ ├── hiring_failed.tpl │ ├── hiring_offered.tpl │ ├── hiring_spawn.tpl │ ├── invitation.tpl │ ├── invoice.html │ ├── invoice.tpl │ ├── invoiceOverdue.tpl │ ├── invoiceThankyou.tpl │ ├── offboarding_keep_fwd_email.tpl │ ├── onboarding.tpl │ ├── paidPayroll.tpl │ ├── referral_inform.tpl │ ├── signature.tpl │ └── weeklydigest.tpl ├── utils │ ├── authutils │ │ ├── auth.go │ │ └── auth_test.go │ ├── currency.go │ ├── erc20.go │ ├── errors.go │ ├── mailutils │ │ └── mailutils.go │ ├── response.go │ ├── strings.go │ ├── strings_test.go │ ├── stringutils │ │ └── strings.go │ ├── testhelper │ │ ├── db.go │ │ └── db_test.go │ └── timeutil │ │ ├── util.go │ │ └── util_test.go ├── view │ ├── asset.go │ ├── auth.go │ ├── auth_test.go │ ├── bank.go │ ├── bank_account.go │ ├── brainery_metric.go │ ├── chapter.go │ ├── client.go │ ├── client_contact.go │ ├── communitynft.go │ ├── company_info.go │ ├── currency.go │ ├── dashboard.go │ ├── delivery_metric.go │ ├── discord_event.go │ ├── earn.go │ ├── earns.go │ ├── employee.go │ ├── event_speaker.go │ ├── feedback.go │ ├── hiring.go │ ├── icy.go │ ├── invoice.go │ ├── memo.go │ ├── metadata.go │ ├── news.go │ ├── organizations.go │ ├── pagination.go │ ├── pagination_view.go │ ├── position.go │ ├── profile.go │ ├── project.go │ ├── research_topic.go │ ├── response.go │ ├── roles.go │ ├── salary.go │ ├── seniority.go │ ├── stack.go │ ├── survey.go │ ├── uuid.go │ ├── uuid_test.go │ ├── valuation.go │ └── work_unit.go └── worker │ └── worker.go └── tools.Dockerfile /.aidigestignore: -------------------------------------------------------------------------------- 1 | Dockerfile 2 | tools.Dockerfile 3 | .env 4 | go.* 5 | devbox.* 6 | .golangci.yml 7 | .gitignore 8 | .air.toml 9 | dbconfig.yml 10 | CODEOWNERS 11 | README.md 12 | docker-compose.yml 13 | Makefile 14 | .github/* 15 | docs/* 16 | cmd/server/main.go 17 | migrations/* 18 | pkg/controller/auth/* 19 | pkg/handler/auth/* 20 | pkg/handler/vault/* 21 | pkg/handler/healthz/* 22 | pkg/handler/dashboard/util/mocks/* 23 | pkg/config/* 24 | pkg/contracts/* 25 | pkg/logger/* 26 | pkg/mw/* 27 | pkg/utils/* 28 | pkg/view/* 29 | pkg/templates/* 30 | **_test.go 31 | **/testdata/* 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /.cursor/rules/mcp-playbook.mdc: -------------------------------------------------------------------------------- 1 | --- 2 | description: 3 | globs: 4 | alwaysApply: false 5 | --- 6 | ALWAYS run the `init_playbook` tool before starting to get instructions on how things should be done and documented. -------------------------------------------------------------------------------- /.github/workflows/ci-test.yml: -------------------------------------------------------------------------------- 1 | on: [pull_request] 2 | 3 | jobs: 4 | ci-test: 5 | runs-on: ubuntu-latest 6 | name: CI testing 7 | steps: 8 | - uses: actions/checkout@v3 9 | - uses: actions/setup-go@v3 10 | with: 11 | go-version: "^1.21" 12 | 13 | - name: Run Test 14 | run: make ci 15 | -------------------------------------------------------------------------------- /.github/workflows/commitlint.yml: -------------------------------------------------------------------------------- 1 | name: Lint Commit Messages 2 | on: [pull_request] 3 | 4 | jobs: 5 | commitlint: 6 | runs-on: ubuntu-latest 7 | steps: 8 | - uses: actions/checkout@v2 9 | with: 10 | fetch-depth: 0 11 | - uses: wagoid/commitlint-github-action@v2 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # IDE and OS 2 | .idea 3 | .vscode 4 | .DS_Store 5 | 6 | # output 7 | bin 8 | log 9 | *.log 10 | *.out 11 | *.out.* 12 | *.test 13 | build 14 | .env 15 | .env.dev 16 | .env.docker 17 | 18 | # dependencies 19 | vendor 20 | tmp -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Default reviewers for every PR 2 | * @huynguyenh @lmquang 3 | .github/ @huynguyenh @lmquang 4 | cmd/ @huynguyenh @lmquang 5 | docs/ @huynguyenh @lmquang 6 | migrations/ @huynguyenh @lmquang 7 | pkg/ @huynguyenh @lmquang 8 | -------------------------------------------------------------------------------- /devbox.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/jetify-com/devbox/0.10.7/.schema/devbox.schema.json", 3 | "packages": [ 4 | "docker@latest", 5 | "docker-compose@latest", 6 | "git@latest", 7 | "qemu@latest", 8 | "vim@latest", 9 | "colima@latest", 10 | "air@latest", 11 | "go@1.21", 12 | "go-swag@1.8.4" 13 | ], 14 | "shell": { 15 | "scripts": { 16 | "test": [ 17 | "echo \"Error: no test specified\" && exit 1" 18 | ] 19 | } 20 | }, 21 | "env": { 22 | "PATH": "/usr/bin:$PWD/.devbox/nix/profile/default/bin:$PATH", 23 | "GOPATH": "$PWD/.devbox/nix/profile/default/share/go" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /docs/changelog/0002-improved-project-head-syncing.md: -------------------------------------------------------------------------------- 1 | ## Improved Project Head Data Syncing from Notion 2 | 3 | This update enhances the synchronization of project head information (such as Sales Person, Tech Lead, and Account Managers) from Notion. Previously, some roles were synced using names, while others used emails. To improve accuracy and consistency, all relevant project head roles will now be synced using their email addresses when available in Notion. 4 | 5 | This change primarily affects the internal data representation and syncing process, leading to more reliable project head information within the system. -------------------------------------------------------------------------------- /migrations/schemas/20221212015001-gen_username_data_for_employee.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | ALTER TABLE "employees" DROP CONSTRAINT IF EXISTS employees_username_key; 3 | -- +migrate StatementBegin 4 | UPDATE employees 5 | SET username = SPLIT_PART(team_email, '@', 1); 6 | -- +migrate StatementEnd 7 | -- +migrate Down 8 | ALTER TABLE "employees" DROP CONSTRAINT IF EXISTS employees_username_key; 9 | UPDATE employees 10 | SET username = NULL; 11 | 12 | ALTER TABLE employees ADD UNIQUE (username); 13 | -------------------------------------------------------------------------------- /migrations/schemas/20221227024809-alter_project_table.sql: -------------------------------------------------------------------------------- 1 | 2 | -- +migrate Up 3 | ALTER TABLE "projects" ADD COLUMN "code" TEXT; 4 | ALTER TABLE projects ADD UNIQUE (code); 5 | 6 | -- +migrate Down 7 | ALTER TABLE "projects" DROP CONSTRAINT IF EXISTS projects_code_key; 8 | ALTER TABLE "projects" DROP COLUMN "code"; 9 | -------------------------------------------------------------------------------- /migrations/schemas/20230105032842-alter_projects_table.sql: -------------------------------------------------------------------------------- 1 | 2 | -- +migrate Up 3 | CREATE TYPE project_functions AS ENUM ( 4 | 'development', 5 | 'learning', 6 | 'training', 7 | 'management' 8 | ); 9 | ALTER TABLE "projects" ADD COLUMN "function" project_functions; 10 | 11 | -- +migrate Down 12 | ALTER TABLE "projects" DROP COLUMN "function"; 13 | DROP TYPE project_functions; 14 | -------------------------------------------------------------------------------- /migrations/schemas/20230106075550-alter_table_add_missing_columns.sql: -------------------------------------------------------------------------------- 1 | 2 | -- +migrate Up 3 | ALTER TABLE "seniorities" ADD COLUMN "level" INT; 4 | ALTER TABLE "employees" ADD COLUMN "organization" TEXT; 5 | 6 | -- +migrate Down 7 | ALTER TABLE "seniorities" DROP COLUMN "level"; 8 | ALTER TABLE "employees" DROP COLUMN "organization"; 9 | -------------------------------------------------------------------------------- /migrations/schemas/20230206045042-alter_employees_table.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | ALTER TABLE employees ADD COLUMN "referred_by" UUID; 3 | ALTER TABLE employees ADD CONSTRAINT employees_referred_by_fkey FOREIGN KEY (referred_by) REFERENCES employees (id); 4 | 5 | -- +migrate Down 6 | ALTER TABLE employees DROP CONSTRAINT IF EXISTS employees_referred_by_fkey; 7 | ALTER TABLE employees DROP COLUMN IF EXISTS "referred_by"; 8 | 9 | -------------------------------------------------------------------------------- /migrations/schemas/20230207063521-alter_projects_table.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | ALTER TABLE projects ADD COLUMN "bank_account_id" UUID; 3 | ALTER TABLE projects ADD CONSTRAINT projects_bank_account_id_fkey FOREIGN KEY (bank_account_id) REFERENCES bank_accounts (id); 4 | 5 | -- +migrate Down 6 | ALTER TABLE projects DROP CONSTRAINT IF EXISTS projects_bank_account_id_fkey; 7 | ALTER TABLE projects DROP COLUMN IF EXISTS "bank_account_id"; 8 | -------------------------------------------------------------------------------- /migrations/schemas/20230215021807-alter_projects_table.sql: -------------------------------------------------------------------------------- 1 | 2 | -- +migrate Up 3 | ALTER TABLE projects ADD COLUMN "organization_id" UUID; 4 | ALTER TABLE projects 5 | ADD CONSTRAINT projects_organizations_id_fkey FOREIGN KEY (organization_id) REFERENCES organizations (id); 6 | 7 | -- +migrate Down 8 | ALTER TABLE projects DROP CONSTRAINT IF EXISTS projects_organizations_id_fkey; 9 | ALTER TABLE projects DROP COLUMN IF EXISTS "organization_id"; 10 | -------------------------------------------------------------------------------- /migrations/schemas/20230222033838-alter_project_slots_table.sql: -------------------------------------------------------------------------------- 1 | 2 | -- +migrate Up 3 | ALTER TABLE project_slots ADD COLUMN note TEXT; 4 | ALTER TABLE project_members ADD COLUMN note TEXT; 5 | 6 | -- +migrate Down 7 | ALTER TABLE project_members DROP COLUMN IF EXISTS note; 8 | ALTER TABLE project_slots DROP COLUMN IF EXISTS note; 9 | -------------------------------------------------------------------------------- /migrations/schemas/20230303090207-alter_audits_table.sql: -------------------------------------------------------------------------------- 1 | 2 | -- +migrate Up 3 | alter table audits 4 | alter column auditor_id drop not null; 5 | 6 | -- +migrate Down 7 | alter table audits 8 | alter column auditor_id set not null; 9 | -------------------------------------------------------------------------------- /migrations/schemas/20230313023453-alter_project_members_table.sql: -------------------------------------------------------------------------------- 1 | 2 | -- +migrate Up 3 | ALTER TABLE project_members ADD COLUMN upsell_commission_rate DECIMAL; 4 | 5 | -- +migrate Down 6 | ALTER TABLE project_members DROP COLUMN IF EXISTS upsell_commission_rate; 7 | -------------------------------------------------------------------------------- /migrations/schemas/20230313023454-add_missing_updated_at_field.sql: -------------------------------------------------------------------------------- 1 | 2 | -- +migrate Up 3 | ALTER TABLE accounting_transactions ADD COLUMN updated_at TIMESTAMP(6) DEFAULT (NOW()); 4 | 5 | -- +migrate Down 6 | ALTER TABLE accounting_transactions DROP COLUMN updated_at; 7 | -------------------------------------------------------------------------------- /migrations/schemas/20230410074637-create_service_table.sql: -------------------------------------------------------------------------------- 1 | 2 | -- +migrate Up 3 | CREATE TABLE IF NOT EXISTS public.operational_services ( 4 | id uuid PRIMARY KEY DEFAULT (uuid()), 5 | created_at TIMESTAMP(6) DEFAULT NOW(), 6 | update_at TIMESTAMP(6) DEFAULT NOW(), 7 | deleted_at TIMESTAMP(6), 8 | name TEXT, 9 | amount INT8, 10 | currency_id UUID REFERENCES public.currencies (id), 11 | note TEXT, 12 | register_date DATE DEFAULT NOW(), 13 | start_at DATE DEFAULT NOW(), 14 | end_at DATE, 15 | is_active BOOLEAN DEFAULT TRUE 16 | ); 17 | -- +migrate Down 18 | DROP TABLE public.operational_services; 19 | -------------------------------------------------------------------------------- /migrations/schemas/20230410074638-add-bank-info.sql: -------------------------------------------------------------------------------- 1 | 2 | -- +migrate Up 3 | alter table public.bank_accounts add column intermediary_bank_address text; 4 | alter table public.bank_accounts add column intermediary_bank_name text; 5 | 6 | -- +migrate Down 7 | alter table public.bank_accounts drop column intermediary_bank_address; 8 | alter table public.bank_accounts drop column intermediary_bank_name; 9 | -------------------------------------------------------------------------------- /migrations/schemas/20230419095551-create-audience-table.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | create table if not exists "audiences" ( 3 | "id" uuid primary key default (uuid()), 4 | "created_at" timestamptz(6) default now(), 5 | "updated_at" timestamptz(6) default now(), 6 | "deleted_at" timestamptz(6), 7 | "email" text, 8 | "full_name" text, 9 | "first_name" text, 10 | "last_name" text, 11 | "source" text, 12 | "notion_id" text, 13 | "subscribed_dwarves_updates" boolean, 14 | "subscribed_techie_story" boolean, 15 | "subscribed_webuild" boolean 16 | ); 17 | 18 | -- +migrate Down 19 | drop table if exists "audiences"; 20 | -------------------------------------------------------------------------------- /migrations/schemas/20230419095552-add_missing_updated_at_field_base_salary.sql: -------------------------------------------------------------------------------- 1 | 2 | -- +migrate Up 3 | ALTER TABLE base_salaries ADD COLUMN updated_at TIMESTAMP(6) DEFAULT (NOW()); 4 | 5 | -- +migrate Down 6 | ALTER TABLE base_salaries DROP COLUMN updated_at; 7 | -------------------------------------------------------------------------------- /migrations/schemas/20230419095553-change_invoice_number_data_type.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | ALTER TABLE invoices ALTER COLUMN discount TYPE DECIMAL USING discount::DECIMAL; 3 | ALTER TABLE invoices ALTER COLUMN tax TYPE DECIMAL USING tax::DECIMAL; 4 | ALTER TABLE invoices ALTER COLUMN sub_total TYPE DECIMAL USING sub_total::DECIMAL; 5 | 6 | -- +migrate Down 7 | ALTER TABLE invoices ALTER COLUMN discount TYPE INTEGER USING discount::INTEGER; 8 | ALTER TABLE invoices ALTER COLUMN tax TYPE INTEGER USING tax::INTEGER; 9 | ALTER TABLE invoices ALTER COLUMN sub_total TYPE INTEGER USING sub_total::INTEGER; 10 | -------------------------------------------------------------------------------- /migrations/schemas/20230509095554-add_discord_log_template.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | create table if not EXISTS discord_log_templates ( 3 | id uuid PRIMARY KEY DEFAULT(uuid()), 4 | deleted_at TIMESTAMP(6), 5 | created_at TIMESTAMP(6) DEFAULT(NOW()), 6 | updated_at TIMESTAMP(6) DEFAULT(NOW()), 7 | 8 | type TEXT, 9 | content TEXT 10 | ); 11 | 12 | -- +migrate Down 13 | drop table discord_log_templates; 14 | -------------------------------------------------------------------------------- /migrations/schemas/20230516000300-alter_employee_drop_not_null_team_email.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | ALTER TABLE employees ALTER COLUMN team_email DROP NOT NULL; 3 | 4 | -- +migrate Down 5 | -------------------------------------------------------------------------------- /migrations/schemas/20230516091724-alter_table_icy_tx_add_unique.sql: -------------------------------------------------------------------------------- 1 | 2 | -- +migrate Up 3 | alter table icy_transactions add constraint unique_icy_txn_src_dest_category unique (src_employee_id, dest_employee_id, category, amount, txn_time); 4 | -- +migrate Down 5 | alter table icy_transactions drop constraint unique_icy_txn_src_dest_category; 6 | -------------------------------------------------------------------------------- /migrations/schemas/20230610100900-alter_roles_table_add_is_show_column.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | ALTER TABLE roles ADD COLUMN is_show BOOL NOT NULL DEFAULT TRUE; 3 | ALTER TABLE roles ADD COLUMN color TEXT; 4 | -- +migrate Down 5 | ALTER TABLE roles DROP COLUMN is_show; 6 | ALTER TABLE roles DROP COLUMN color; 7 | -------------------------------------------------------------------------------- /migrations/schemas/20230622072538-add_coors_col_in_employees.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | DROP VIEW IF EXISTS vw_employees_recently_joined; 3 | ALTER TABLE employees ADD COLUMN lat TEXT DEFAULT NULL; 4 | ALTER TABLE employees ADD COLUMN long TEXT DEFAULT NULL; 5 | 6 | CREATE OR REPLACE VIEW vw_employees_recently_joined AS 7 | SELECT * 8 | FROM employees 9 | WHERE joined_date BETWEEN CURRENT_DATE - INTERVAL '7 days' AND CURRENT_DATE; 10 | -- +migrate Down 11 | ALTER TABLE employees DROP COLUMN lat CASCADE; 12 | ALTER TABLE employees DROP COLUMN long CASCADE; 13 | -------------------------------------------------------------------------------- /migrations/schemas/20230718143052-add-view-weekly-delivery-metrics.sql: -------------------------------------------------------------------------------- 1 | 2 | -- +migrate Up 3 | CREATE INDEX delivery_metrics_date_idx ON delivery_metrics ((date::date) DESC NULLS LAST); 4 | 5 | CREATE VIEW "vw_weekly_delivery_metrics" AS 6 | SELECT "date", 7 | SUM(weight) AS "sum_weight", 8 | SUM(effort) AS "sum_effort" 9 | FROM delivery_metrics 10 | GROUP BY "date"; 11 | 12 | -- +migrate Down 13 | DROP VIEW "vw_weekly_delivery_metrics"; 14 | 15 | DROP INDEX IF EXISTS delivery_metrics_date_idx; 16 | -------------------------------------------------------------------------------- /migrations/schemas/20230720050455-add-view-monthly-lelivery-metrics.sql: -------------------------------------------------------------------------------- 1 | 2 | -- +migrate Up 3 | CREATE VIEW "vw_monthly_delivery_metrics" AS 4 | SELECT 5 | DATE_TRUNC('month', date) as "month", 6 | SUM(weight) AS "sum_weight", 7 | SUM(effort) AS "sum_effort" 8 | FROM delivery_metrics 9 | GROUP BY DATE_TRUNC('month', date) 10 | ORDER BY "month" DESC; 11 | 12 | -- +migrate Down 13 | DROP VIEW "vw_monthly_delivery_metrics"; 14 | -------------------------------------------------------------------------------- /migrations/schemas/20231111011111-add_currency_conversion_rate.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | CREATE TABLE IF NOT EXISTS conversion_rates ( 3 | id UUID PRIMARY KEY DEFAULT (UUID()), 4 | deleted_at TIMESTAMP(6), 5 | created_at TIMESTAMP(6) DEFAULT (now()), 6 | updated_at TIMESTAMP(6) DEFAULT (now()), 7 | 8 | currency_id UUID DEFAULT NULL, 9 | to_usd DECIMAL, 10 | to_vnd DECIMAL 11 | ); 12 | 13 | ALTER TABLE conversion_rates 14 | ADD CONSTRAINT conversion_rates_currency_id_fkey FOREIGN KEY (currency_id) REFERENCES currencies (id); 15 | 16 | -- +migrate Down 17 | DROP TABLE IF EXISTS conversion_rates; 18 | -------------------------------------------------------------------------------- /migrations/schemas/20231112134909-init-config.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | CREATE TABLE IF NOT EXISTS configs ( 3 | id uuid PRIMARY KEY DEFAULT (uuid()), 4 | deleted_at TIMESTAMP(6), 5 | created_at TIMESTAMP(6) DEFAULT (now()), 6 | updated_at TIMESTAMP(6) DEFAULT (now()), 7 | key TEXT NOT NULL, 8 | value TEXT NOT NULL 9 | ); 10 | 11 | ALTER TABLE configs ADD UNIQUE (key); 12 | 13 | -- +migrate Down 14 | DROP TABLE IF EXISTS configs; 15 | -------------------------------------------------------------------------------- /migrations/schemas/20231130215800-add-advance-salary-amount.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | ALTER TABLE payrolls ADD COLUMN salary_advance_amount INT8; 3 | 4 | -- +migrate Down 5 | ALTER TABLE payrolls DROP COLUMN salary_advance_amount; 6 | -------------------------------------------------------------------------------- /migrations/schemas/20231130215800-change-advance-salary-amount-type.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | ALTER TABLE payrolls 3 | ALTER COLUMN salary_advance_amount TYPE FLOAT8 USING salary_advance_amount::FLOAT8; 4 | 5 | ALTER TABLE payrolls 6 | ALTER COLUMN salary_advance_amount SET DEFAULT 0; 7 | 8 | -- +migrate Down 9 | 10 | ALTER TABLE payrolls 11 | ALTER COLUMN salary_advance_amount TYPE INT8 USING salary_advance_amount::INT8; 12 | 13 | ALTER TABLE payrolls 14 | ALTER COLUMN salary_advance_amount SET DEFAULT NULL; -------------------------------------------------------------------------------- /migrations/schemas/20240318011415-add_invoice_bonus.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | ALTER TABLE "invoices" ADD COLUMN "bonus" DECIMAL; 3 | ALTER TABLE "invoices" ADD COLUMN "total_without_bonus" DECIMAL; 4 | 5 | -- +migrate Down 6 | ALTER TABLE "invoices" DROP COLUMN "bonus"; 7 | ALTER TABLE "invoices" DROP COLUMN "total_without_bonus"; 8 | -------------------------------------------------------------------------------- /migrations/schemas/20240417112538-add_memo_logs_table.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | CREATE TABLE IF NOT EXISTS memo_logs ( 3 | id UUID PRIMARY KEY DEFAULT (UUID()), 4 | deleted_at TIMESTAMP(6), 5 | created_at TIMESTAMP(6) DEFAULT (now()), 6 | updated_at TIMESTAMP(6) DEFAULT (now()), 7 | 8 | title TEXT NOT NULL, 9 | url TEXT NOT NULL, 10 | authors JSONB, 11 | tags JSONB, 12 | description TEXT, 13 | published_at TIMESTAMP(6) NOT NULL, 14 | reward DECIMAL 15 | ); 16 | 17 | -- +migrate Down 18 | DROP TABLE IF EXISTS memo_logs; 19 | -------------------------------------------------------------------------------- /migrations/schemas/20240513105259-add_table_memo_authors_and_unique_memo_link.sql: -------------------------------------------------------------------------------- 1 | 2 | -- +migrate Up 3 | CREATE TABLE IF NOT EXISTS memo_authors ( 4 | memo_log_id UUID NOT NULL REFERENCES memo_logs(id), 5 | discord_account_id UUID NOT NULL REFERENCES discord_accounts(id), 6 | created_at TIMESTAMP(6) DEFAULT (now()), 7 | PRIMARY KEY (memo_log_id, discord_account_id) 8 | ); 9 | 10 | ALTER TABLE memo_logs ADD UNIQUE ("url"); 11 | -- +migrate Down 12 | ALTER TABLE memo_logs DROP CONSTRAINT memo_logs_url_key; 13 | 14 | DROP TABLE IF EXISTS memo_authors; 15 | -------------------------------------------------------------------------------- /migrations/schemas/20240513164949-remove_column_memo_logs_authors.sql: -------------------------------------------------------------------------------- 1 | 2 | -- +migrate Up 3 | ALTER TABLE memo_logs DROP COLUMN IF EXISTS authors; 4 | -- +migrate Down 5 | ALTER TABLE memo_logs ADD COLUMN authors JSONB; 6 | -------------------------------------------------------------------------------- /migrations/schemas/20240627064435-add_memo_log_category.sql: -------------------------------------------------------------------------------- 1 | 2 | -- +migrate Up 3 | ALTER TABLE memo_logs ADD COLUMN "category" TEXT[] default '{}'::TEXT[]; 4 | 5 | -- +migrate Down 6 | ALTER TABLE memo_logs DROP COLUMN "category"; 7 | -------------------------------------------------------------------------------- /migrations/schemas/20240906073841-dropevent_speakers_event_id_discord_account_id_key.sql: -------------------------------------------------------------------------------- 1 | 2 | -- +migrate Up 3 | ALTER TABLE event_speakers 4 | DROP CONSTRAINT IF EXISTS event_speakers_event_id_discord_account_id_key; 5 | 6 | ALTER TABLE event_speakers 7 | ADD CONSTRAINT event_speakers_topic_key UNIQUE (topic); 8 | 9 | 10 | 11 | -- +migrate Down 12 | ALTER TABLE event_speakers 13 | DROP CONSTRAINT IF EXISTS event_speakers_topic_key; 14 | 15 | ALTER TABLE event_speakers ADD CONSTRAINT event_speakers_event_id_discord_account_id_key UNIQUE (event_id, discord_account_id); 16 | -------------------------------------------------------------------------------- /migrations/schemas/20240918064436-add_table_physical_checkin_transactions.sql: -------------------------------------------------------------------------------- 1 | 2 | -- +migrate Up 3 | CREATE TABLE physical_checkin_transactions ( 4 | id uuid PRIMARY KEY DEFAULT (uuid()), 5 | employee_id UUID REFERENCES employees(id) NOT NULL, 6 | date DATE NOT NULL, 7 | icy_amount FLOAT8 DEFAULT 0.0, 8 | mochi_tx_id INTEGER 9 | ); 10 | -- add unique constraint 11 | CREATE UNIQUE INDEX physical_checkin_transactions_employee_id_date_idx ON physical_checkin_transactions(employee_id, date); 12 | 13 | 14 | -- +migrate Down 15 | DROP TABLE physical_checkin_transactions; 16 | 17 | 18 | -------------------------------------------------------------------------------- /migrations/schemas/20241120044604-alter_table_employees_add_iskeepfwdemail.sql: -------------------------------------------------------------------------------- 1 | 2 | -- +migrate Up 3 | ALTER TABLE employees ADD COLUMN is_keep_fwd_email BOOLEAN DEFAULT FALSE; 4 | 5 | -- +migrate Down 6 | ALTER TABLE employees DROP COLUMN is_keep_fwd_email; 7 | -------------------------------------------------------------------------------- /migrations/schemas/20250122042534-alter_table_projects_add_project_artifact_link.sql: -------------------------------------------------------------------------------- 1 | 2 | -- +migrate Up 3 | ALTER TABLE projects ADD COLUMN artifact_link VARCHAR(255); 4 | 5 | -- +migrate Down 6 | ALTER TABLE projects DROP COLUMN artifact_link; 7 | -------------------------------------------------------------------------------- /migrations/schemas/20250123085334-add_source_doc_links_to_projects.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | ALTER TABLE projects 3 | ADD COLUMN source_link VARCHAR(255), 4 | ADD COLUMN doc_link VARCHAR(255); 5 | 6 | -- +migrate Down 7 | ALTER TABLE projects 8 | DROP COLUMN source_link, 9 | DROP COLUMN doc_link; 10 | -------------------------------------------------------------------------------- /migrations/schemas/20250525160000_add_deal_closing_to_project_head_positions_enum.sql: -------------------------------------------------------------------------------- 1 | -- Add 'deal-closing' to the project_head_positions ENUM type 2 | -- +migrate Up 3 | ALTER TYPE project_head_positions ADD VALUE IF NOT EXISTS 'deal-closing'; 4 | 5 | -- +migrate Down 6 | -- No-op: removing ENUM values is not supported in PostgreSQL 7 | SELECT 8 | 1; 9 | -------------------------------------------------------------------------------- /migrations/seed/configs.sql: -------------------------------------------------------------------------------- 1 | INSERT INTO public.configs 2 | (id, deleted_at, created_at, updated_at, key, value) 3 | SELECT '5a02645d-bbfd-4da5-9582-3d4a96bcfeb8', NULL, '2023-12-11 09:50:25.714604', '2023-12-11 09:50:25.714604', 'salary-advance-max-cap', '25' 4 | WHERE NOT EXISTS ( 5 | SELECT 1 6 | FROM public.configs 7 | WHERE key = 'salary-advance-max-cap' 8 | ); 9 | 10 | INSERT INTO public.configs 11 | (id, deleted_at, created_at, updated_at, key, value) 12 | SELECT '1899da85-b29a-486c-b54b-8822a085c02f', NULL, '2023-12-11 09:50:25.714604', '2023-12-11 09:50:25.714604', 'icy-usd-rate', '1.5' 13 | WHERE NOT EXISTS ( 14 | SELECT 1 15 | FROM public.configs 16 | WHERE key = 'icy-usd-rate' 17 | ); 18 | 19 | -------------------------------------------------------------------------------- /migrations/seed/engagement_metrics.sql: -------------------------------------------------------------------------------- 1 | -- TODO: dump "real" data for testing -------------------------------------------------------------------------------- /migrations/seed/project_stacks.sql: -------------------------------------------------------------------------------- 1 | INSERT INTO public.project_stacks (id, deleted_at, created_at, updated_at, project_id, stack_id) VALUES 2 | ('6b89cc06-33ca-4f48-825a-ab20da5cb287', NULL, '2022-11-11 18:39:34.923619', '2022-11-11 18:39:34.923619', '8dc3be2e-19a4-4942-8a79-56db391a0b15', '0ecf47c8-cca4-4c30-94bb-054b1124c44f'), 3 | ('da982888-1727-4c06-8e8a-86aff1f80f89', NULL, '2022-11-11 18:39:34.923619', '2022-11-11 18:39:34.923619', '8dc3be2e-19a4-4942-8a79-56db391a0b15', 'fa0f4e46-7eab-4e5c-9d31-30489e69fe2e'), 4 | ('371d797f-a639-4869-8026-67e682c6da4a', NULL, '2022-11-11 18:39:34.923619', '2022-11-11 18:39:34.923619', '8dc3be2e-19a4-4942-8a79-56db391a0b15', 'b403ef95-4269-4830-bbb6-8e56e5ec0af4'); 5 | -------------------------------------------------------------------------------- /pkg/config/env_reader.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "github.com/spf13/viper" 5 | ) 6 | 7 | // ENVReader load config from env 8 | type ENVReader struct { 9 | } 10 | 11 | // NewENVLoader create new env loader 12 | func NewENVLoader() Loader { 13 | return &ENVReader{} 14 | } 15 | 16 | // Load env into viper 17 | func (r *ENVReader) Load(v viper.Viper) (*viper.Viper, error) { 18 | v.AutomaticEnv() 19 | return &v, nil 20 | } 21 | -------------------------------------------------------------------------------- /pkg/constant/constant.go: -------------------------------------------------------------------------------- 1 | package constant 2 | 3 | const ( 4 | RegexPatternDiscordChannelID = `<#(\d+)>` 5 | RegexPatternDiscordID = `<@(\d+)>` 6 | RegexPatternEmail = `\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+\b` 7 | RegexPatternIcyReward = ` (\d+)` 8 | RegexPatternNumber = `\d{18,}` 9 | RegexPatternUrl = `((?:https?://)[^\s]+)` 10 | RegexPatternGithub = `gh:(\w+)` 11 | RegexPatternDescription = `d:"(.*?)"` 12 | RegexPatternTime = `t:(\w+)` 13 | ) 14 | -------------------------------------------------------------------------------- /pkg/controller/auth/errors.go: -------------------------------------------------------------------------------- 1 | package auth 2 | 3 | import "errors" 4 | 5 | var ( 6 | ErrUserInactivated = errors.New("user is inactivated") 7 | ErrEmptyPrimaryEmail = errors.New("empty primary email") 8 | ErrUserNotFound = errors.New("user is not found") 9 | ErrRoleNotfound = errors.New("role is not found") 10 | ) 11 | -------------------------------------------------------------------------------- /pkg/controller/auth/me.go: -------------------------------------------------------------------------------- 1 | package auth 2 | 3 | import ( 4 | "errors" 5 | 6 | "gorm.io/gorm" 7 | 8 | "github.com/dwarvesf/fortress-api/pkg/model" 9 | ) 10 | 11 | func (c *controller) Me(userID string) (*model.Employee, []*model.Permission, error) { 12 | e, err := c.store.Employee.One(c.repo.DB(), userID, false) 13 | if err != nil { 14 | if errors.Is(err, gorm.ErrRecordNotFound) { 15 | return nil, nil, ErrUserNotFound 16 | } 17 | 18 | return nil, nil, err 19 | } 20 | 21 | perms, err := c.store.Permission.GetByEmployeeID(c.repo.DB(), userID) 22 | if err != nil { 23 | return nil, nil, err 24 | } 25 | 26 | return e, perms, nil 27 | } 28 | -------------------------------------------------------------------------------- /pkg/controller/client/detail.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | 6 | "github.com/dwarvesf/fortress-api/pkg/model" 7 | ) 8 | 9 | func (r *controller) Detail(c *gin.Context, clientID string) (*model.Client, error) { 10 | client, err := r.store.Client.One(r.repo.DB(), clientID) 11 | if err != nil { 12 | return nil, err 13 | } 14 | return client, nil 15 | } 16 | -------------------------------------------------------------------------------- /pkg/controller/client/errors.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import "errors" 4 | 5 | var ( 6 | ErrInvalidClientID = errors.New("invalid client id") 7 | ErrInvalidClientContactID = errors.New("invalid client contact id") 8 | ErrClientNotFound = errors.New("client not found") 9 | ErrClientContactNotFound = errors.New("client contact not found") 10 | ErrMismatchClientID = errors.New("mismatch client id") 11 | ) 12 | -------------------------------------------------------------------------------- /pkg/controller/client/list.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | 6 | "github.com/dwarvesf/fortress-api/pkg/model" 7 | ) 8 | 9 | func (r *controller) List(c *gin.Context) ([]*model.Client, error) { 10 | clients, err := r.store.Client.All(r.repo.DB(), false, false) 11 | if err != nil { 12 | return nil, err 13 | } 14 | 15 | return clients, nil 16 | } 17 | 18 | func (r *controller) PublicList(c *gin.Context) ([]*model.Client, error) { 19 | clients, err := r.store.Client.All(r.repo.DB(), true, true) 20 | if err != nil { 21 | return nil, err 22 | } 23 | 24 | return clients, nil 25 | } 26 | -------------------------------------------------------------------------------- /pkg/controller/communitynft/errors.go: -------------------------------------------------------------------------------- 1 | package communitynft 2 | 3 | import "errors" 4 | 5 | var ( 6 | ErrInvalidTokenID = errors.New("invalid token id") 7 | ErrTokenNotFound = errors.New("token not found") 8 | ErrMochiProfileNotFound = errors.New("mochi profile not found") 9 | ) 10 | -------------------------------------------------------------------------------- /pkg/controller/companyinfo/list.go: -------------------------------------------------------------------------------- 1 | package companyinfo 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | 6 | "github.com/dwarvesf/fortress-api/pkg/model" 7 | ) 8 | 9 | func (r *controller) List(c *gin.Context) ([]*model.CompanyInfo, error) { 10 | companyInfos, err := r.store.CompanyInfo.All(r.repo.DB()) 11 | if err != nil { 12 | return nil, err 13 | } 14 | 15 | return companyInfos, nil 16 | } 17 | -------------------------------------------------------------------------------- /pkg/controller/conversionrate/errors.go: -------------------------------------------------------------------------------- 1 | package conversionrate 2 | 3 | var () 4 | -------------------------------------------------------------------------------- /pkg/controller/dynamicevents/dynamic_events.go: -------------------------------------------------------------------------------- 1 | package dynamicevents 2 | 3 | import ( 4 | "github.com/dwarvesf/fortress-api/pkg/config" 5 | "github.com/dwarvesf/fortress-api/pkg/logger" 6 | "github.com/dwarvesf/fortress-api/pkg/service" 7 | "github.com/dwarvesf/fortress-api/pkg/store" 8 | ) 9 | 10 | type controller struct { 11 | store *store.Store 12 | service *service.Service 13 | logger logger.Logger 14 | config *config.Config 15 | } 16 | 17 | func New(store *store.Store, service *service.Service, logger logger.Logger, cfg *config.Config) IController { 18 | return &controller{ 19 | store: store, 20 | service: service, 21 | logger: logger, 22 | config: cfg, 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /pkg/controller/dynamicevents/interface.go: -------------------------------------------------------------------------------- 1 | package dynamicevents 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/dwarvesf/fortress-api/pkg/model" 7 | ) 8 | 9 | type IController interface { 10 | CreateEvents(ctx context.Context, data model.DynamicEvent) error 11 | } 12 | -------------------------------------------------------------------------------- /pkg/controller/earn/interface.go: -------------------------------------------------------------------------------- 1 | package earn 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/dwarvesf/fortress-api/pkg/model" 7 | ) 8 | 9 | type IController interface { 10 | ListEarn(ctx context.Context) ([]model.Earn, error) 11 | } 12 | -------------------------------------------------------------------------------- /pkg/controller/earn/new.go: -------------------------------------------------------------------------------- 1 | package earn 2 | 3 | import ( 4 | "github.com/dwarvesf/fortress-api/pkg/config" 5 | "github.com/dwarvesf/fortress-api/pkg/logger" 6 | "github.com/dwarvesf/fortress-api/pkg/service" 7 | "github.com/dwarvesf/fortress-api/pkg/store" 8 | ) 9 | 10 | type controller struct { 11 | store *store.Store 12 | service *service.Service 13 | logger logger.Logger 14 | config *config.Config 15 | repo store.DBRepo 16 | } 17 | 18 | func New(store *store.Store, repo store.DBRepo, service *service.Service, logger logger.Logger, cfg *config.Config) IController { 19 | return &controller{ 20 | store: store, 21 | service: service, 22 | logger: logger, 23 | config: cfg, 24 | repo: repo, 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /pkg/controller/invoice/errors.go: -------------------------------------------------------------------------------- 1 | package invoice 2 | 3 | import "errors" 4 | 5 | var ( 6 | ErrBankAccountNotFound = errors.New("bank account not found") 7 | ErrCouldNotGetTheLatestInvoice = errors.New("could not get the latest invoice") 8 | ErrCouldNotGetTheNextInvoiceNumber = errors.New("could not get the next invoice number") 9 | ErrInvoiceNotFound = errors.New("invoice not found") 10 | ErrInvoiceStatusAlready = errors.New("invoice status already") 11 | ErrProjectNotFound = errors.New("project not found") 12 | ErrSenderNotFound = errors.New("sender not found") 13 | ) 14 | -------------------------------------------------------------------------------- /pkg/controller/news/interface.go: -------------------------------------------------------------------------------- 1 | package news 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/dwarvesf/fortress-api/pkg/model" 7 | ) 8 | 9 | type IController interface { 10 | FetchLobstersNews(ctx context.Context, tag string) ([]model.News, error) 11 | FetchRedditNews(ctx context.Context, tag string) ([]model.News, error) 12 | } 13 | -------------------------------------------------------------------------------- /pkg/controller/news/new.go: -------------------------------------------------------------------------------- 1 | package news 2 | 3 | import ( 4 | "github.com/dwarvesf/fortress-api/pkg/config" 5 | "github.com/dwarvesf/fortress-api/pkg/logger" 6 | "github.com/dwarvesf/fortress-api/pkg/service" 7 | "github.com/dwarvesf/fortress-api/pkg/store" 8 | ) 9 | 10 | type controller struct { 11 | store *store.Store 12 | service *service.Service 13 | logger logger.Logger 14 | config *config.Config 15 | } 16 | 17 | func New(store *store.Store, service *service.Service, logger logger.Logger, cfg *config.Config) IController { 18 | return &controller{ 19 | store: store, 20 | service: service, 21 | logger: logger, 22 | config: cfg, 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /pkg/handler/accounting/service.go: -------------------------------------------------------------------------------- 1 | package accounting 2 | 3 | import "github.com/gin-gonic/gin" 4 | 5 | type IHandler interface { 6 | CreateAccountingTodo(c *gin.Context) 7 | } 8 | -------------------------------------------------------------------------------- /pkg/handler/asset/errs/errors.go: -------------------------------------------------------------------------------- 1 | package errs 2 | 3 | import "errors" 4 | 5 | var ( 6 | ErrEmployeeNotFound = errors.New("employee not found") 7 | ErrProjectNotFound = errors.New("project not found") 8 | ErrInvalidFileExtension = errors.New("invalid file extension") 9 | ErrInvalidFileType = errors.New("invalid file type") 10 | ErrInvalidFileSize = errors.New("invalid file size") 11 | ErrFileAlreadyExisted = errors.New("file already existed") 12 | ) 13 | -------------------------------------------------------------------------------- /pkg/handler/asset/interface.go: -------------------------------------------------------------------------------- 1 | package asset 2 | 3 | import "github.com/gin-gonic/gin" 4 | 5 | type IHandler interface { 6 | Upload(c *gin.Context) 7 | } 8 | -------------------------------------------------------------------------------- /pkg/handler/audit/errs/errors.go: -------------------------------------------------------------------------------- 1 | package errs 2 | 3 | import "errors" 4 | 5 | var ( 6 | ErrFailedToGetFlag = errors.New("failed to get flag") 7 | ErrMissingAuditorInAudit = errors.New("missing auditor in audit") 8 | ErrMissingProjectInAudit = errors.New("missing project in audit") 9 | ) 10 | -------------------------------------------------------------------------------- /pkg/handler/audit/interface.go: -------------------------------------------------------------------------------- 1 | package audit 2 | 3 | import "github.com/gin-gonic/gin" 4 | 5 | type IHandler interface { 6 | Sync(c *gin.Context) 7 | } 8 | -------------------------------------------------------------------------------- /pkg/handler/auth/auth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dwarvesf/fortress-api/86623ffbd0497624a19056e7d00c32ff2d0a39d0/pkg/handler/auth/auth.png -------------------------------------------------------------------------------- /pkg/handler/auth/interface.go: -------------------------------------------------------------------------------- 1 | package auth 2 | 3 | import "github.com/gin-gonic/gin" 4 | 5 | type IHandler interface { 6 | Auth(c *gin.Context) 7 | Me(c *gin.Context) 8 | CreateAPIKey(c *gin.Context) 9 | } 10 | -------------------------------------------------------------------------------- /pkg/handler/auth/request/request.go: -------------------------------------------------------------------------------- 1 | package request 2 | 3 | type CreateAPIKeyInput struct { 4 | RoleID string `json:"roleID" form:"roleID"` 5 | } 6 | -------------------------------------------------------------------------------- /pkg/handler/bankaccount/interface.go: -------------------------------------------------------------------------------- 1 | package bankaccount 2 | 3 | import "github.com/gin-gonic/gin" 4 | 5 | type IHandler interface { 6 | List(c *gin.Context) 7 | } 8 | -------------------------------------------------------------------------------- /pkg/handler/brainerylogs/errs/errors.go: -------------------------------------------------------------------------------- 1 | package errs 2 | 3 | import "errors" 4 | 5 | var ( 6 | ErrInvalidPublishedAt = errors.New("cannot parse publishedAt") 7 | ErrInvalidDateFormat = errors.New("invalid date format") 8 | ) 9 | -------------------------------------------------------------------------------- /pkg/handler/brainerylogs/interface.go: -------------------------------------------------------------------------------- 1 | package brainerylogs 2 | 3 | import "github.com/gin-gonic/gin" 4 | 5 | type IHandler interface { 6 | Create(c *gin.Context) 7 | GetMetrics(c *gin.Context) 8 | Sync(c *gin.Context) 9 | } 10 | -------------------------------------------------------------------------------- /pkg/handler/client/errs/errors.go: -------------------------------------------------------------------------------- 1 | package errs 2 | 3 | import "errors" 4 | 5 | var ( 6 | ErrInvalidClientID = errors.New("invalid client id") 7 | ErrInvalidClientContactID = errors.New("invalid client contact id") 8 | ErrClientNotFound = errors.New("client not found") 9 | ) 10 | -------------------------------------------------------------------------------- /pkg/handler/client/interface.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import "github.com/gin-gonic/gin" 4 | 5 | type IHandler interface { 6 | Create(c *gin.Context) 7 | List(c *gin.Context) 8 | Detail(c *gin.Context) 9 | Update(c *gin.Context) 10 | Delete(c *gin.Context) 11 | 12 | PublicList(c *gin.Context) 13 | } 14 | -------------------------------------------------------------------------------- /pkg/handler/client/testdata/delete/200.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "message": "ok" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/client/testdata/delete/404.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "client not found" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/client/testdata/detail/404.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "client not found" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/client/testdata/update_client/200.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "message": "ok" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/client/testdata/update_client/404.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "client not found" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/communitynft/errs/errors.go: -------------------------------------------------------------------------------- 1 | package errs 2 | 3 | import "errors" 4 | 5 | var ( 6 | ErrInvalidTokenID = errors.New("invalid token id") 7 | ErrTokenNotFound = errors.New("token not found") 8 | ) 9 | -------------------------------------------------------------------------------- /pkg/handler/communitynft/interface.go: -------------------------------------------------------------------------------- 1 | package communitynft 2 | 3 | import "github.com/gin-gonic/gin" 4 | 5 | type IHandler interface { 6 | GetNftMetadata(c *gin.Context) 7 | } 8 | -------------------------------------------------------------------------------- /pkg/handler/companyinfo/interface.go: -------------------------------------------------------------------------------- 1 | package companyinfo 2 | 3 | import "github.com/gin-gonic/gin" 4 | 5 | type IHandler interface { 6 | List(c *gin.Context) 7 | } 8 | -------------------------------------------------------------------------------- /pkg/handler/conversionrate/interface.go: -------------------------------------------------------------------------------- 1 | package conversionrate 2 | 3 | import "github.com/gin-gonic/gin" 4 | 5 | type IHandler interface { 6 | List(c *gin.Context) 7 | Sync(c *gin.Context) 8 | } 9 | -------------------------------------------------------------------------------- /pkg/handler/dashboard/errs/errors.go: -------------------------------------------------------------------------------- 1 | package errs 2 | 3 | import "errors" 4 | 5 | var ( 6 | ErrInvalidProjectID = errors.New("invalid project ID") 7 | ErrProjectNotFound = errors.New("project not found") 8 | ErrEventNotFound = errors.New("event not found") 9 | ErrProjectNotionNotFound = errors.New("project notion not found") 10 | ErrInvalidEngagementDashboardFilter = errors.New("invalid engagement dashboard filter") 11 | ErrInvalidStartDate = errors.New("invalid startDate") 12 | ErrInvalidWorkUnitDistributionType = errors.New("invalid work unit distribution type") 13 | ErrInvalidWorkUnitDistributionSort = errors.New("invalid sort value") 14 | ) 15 | -------------------------------------------------------------------------------- /pkg/handler/dashboard/interface.go: -------------------------------------------------------------------------------- 1 | package dashboard 2 | 3 | import "github.com/gin-gonic/gin" 4 | 5 | type IHandler interface { 6 | GetProjectSizes(c *gin.Context) 7 | GetWorkSurveys(c *gin.Context) 8 | GetActionItemReports(c *gin.Context) 9 | GetEngineeringHealth(c *gin.Context) 10 | GetAudits(c *gin.Context) 11 | GetActionItemSquashReports(c *gin.Context) 12 | GetSummary(c *gin.Context) 13 | GetResourcesAvailability(c *gin.Context) 14 | GetEngagementInfo(c *gin.Context) 15 | GetEngagementInfoDetail(c *gin.Context) 16 | GetResourceUtilization(c *gin.Context) 17 | GetWorkUnitDistribution(c *gin.Context) 18 | GetWorkUnitDistributionSummary(c *gin.Context) 19 | GetResourceWorkSurveySummaries(c *gin.Context) 20 | } 21 | -------------------------------------------------------------------------------- /pkg/handler/dashboard/testdata/action_item_squash/project_not_found.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "project not found" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/dashboard/testdata/action_items/200_with_project_id.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "quarter": "Q1/2022", 5 | "high": 1, 6 | "medium": 1, 7 | "low": 1, 8 | "trend": { 9 | "high": 0, 10 | "medium": 0, 11 | "low": 0 12 | } 13 | }, 14 | { 15 | "quarter": "Q2/2022", 16 | "high": 2, 17 | "medium": 2, 18 | "low": 2, 19 | "trend": { 20 | "high": 100, 21 | "medium": 100, 22 | "low": 100 23 | } 24 | } 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /pkg/handler/dashboard/testdata/engagement_info/no_record.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [] 3 | } 4 | -------------------------------------------------------------------------------- /pkg/handler/dashboard/testdata/engagement_info_detail/invalid_filter.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid engagement dashboard filter" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/dashboard/testdata/engagement_info_detail/invalid_start_date.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid startDate" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/dashboard/testdata/get_resource_work_survey_summaries/200_with_keyword.json: -------------------------------------------------------------------------------- 1 | { 2 | "page": 0, 3 | "size": 999, 4 | "sort": "", 5 | "total": 0, 6 | "data": [ 7 | { 8 | "type": "workload", 9 | "dates": [], 10 | "data": null 11 | }, 12 | { 13 | "type": "deadline", 14 | "dates": [], 15 | "data": null 16 | }, 17 | { 18 | "type": "learning", 19 | "dates": [], 20 | "data": null 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /pkg/handler/dashboard/testdata/project_sizes/200.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "id": "8dc3be2e-19a4-4942-8a79-56db391a0b15", 5 | "name": "Fortress", 6 | "code": "fortress", 7 | "avatar": "", 8 | "size": 5 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /pkg/handler/dashboard/testdata/work_unit_distribution/400_invalid_sort.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid sort value" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/dashboard/testdata/work_unit_distribution/400_invalid_type.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid work unit distribution type" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/dashboard/testdata/work_unit_distribution_summary/200.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": { 3 | "learning": 50, 4 | "development": 33.33, 5 | "management": 16.67, 6 | "training": 0 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /pkg/handler/dashboard/util/interface.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import "time" 4 | 5 | type IUtil interface { 6 | TimeNow() time.Time 7 | } 8 | -------------------------------------------------------------------------------- /pkg/handler/dashboard/util/util.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import "time" 4 | 5 | type util struct{} 6 | 7 | func New() IUtil { 8 | return &util{} 9 | } 10 | 11 | func (u *util) TimeNow() time.Time { 12 | return time.Now() 13 | } 14 | -------------------------------------------------------------------------------- /pkg/handler/deliverymetric/interface.go: -------------------------------------------------------------------------------- 1 | package deliverymetric 2 | 3 | import "github.com/gin-gonic/gin" 4 | 5 | type IHandler interface { 6 | GetWeeklyReport(c *gin.Context) 7 | GetMonthlyReport(c *gin.Context) 8 | GetWeeklyLeaderBoard(c *gin.Context) 9 | GetMonthlyLeaderBoard(c *gin.Context) 10 | 11 | GetWeeklyReportDiscordMsg(c *gin.Context) 12 | GetMonthlyReportDiscordMsg(c *gin.Context) 13 | 14 | Sync(c *gin.Context) 15 | } 16 | -------------------------------------------------------------------------------- /pkg/handler/discord/errs/errors.go: -------------------------------------------------------------------------------- 1 | package errs 2 | 3 | import "errors" 4 | 5 | var ( 6 | ErrEmptyReportView = errors.New("view is empty") 7 | ErrEmptyChannelID = errors.New("channelID is empty") 8 | ErrEmptyGuildID = errors.New("guildID is empty") 9 | ErrEmptyCreatorID = errors.New("creatorID is empty") 10 | ErrEmptyName = errors.New("name is empty") 11 | ErrEmptyDate = errors.New("date is nil") 12 | ErrEmptyID = errors.New("discord user id is nil") 13 | ErrEmptyTopic = errors.New("topic is nil") 14 | ) 15 | -------------------------------------------------------------------------------- /pkg/handler/discord/request/top_memo_authors.go: -------------------------------------------------------------------------------- 1 | package request 2 | 3 | import "errors" 4 | 5 | type TopMemoAuthorsInput struct { 6 | Limit int `json:"limit"` 7 | Days int `json:"days"` 8 | } 9 | 10 | func (i *TopMemoAuthorsInput) Validate() error { 11 | if i.Limit <= 0 { 12 | return errors.New("limit must be greater than 0") 13 | } 14 | if i.Days <= 0 { 15 | return errors.New("days must be greater than 0") 16 | } 17 | return nil 18 | } 19 | -------------------------------------------------------------------------------- /pkg/handler/dynamicevents/interface.go: -------------------------------------------------------------------------------- 1 | package dynamicevents 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | ) 6 | 7 | type IHandler interface { 8 | Events(c *gin.Context) 9 | } 10 | -------------------------------------------------------------------------------- /pkg/handler/dynamicevents/request/request.go: -------------------------------------------------------------------------------- 1 | package request 2 | 3 | import ( 4 | "encoding/json" 5 | ) 6 | 7 | // DynamicEventRequest represents the incoming request structure 8 | type DynamicEventRequest struct { 9 | Type string `json:"type" binding:"required"` 10 | Data json.RawMessage `json:"data" binding:"required"` 11 | } 12 | 13 | // DynamicEventData represents the expected input data structure 14 | type DynamicEventData struct { 15 | Data json.RawMessage `json:"data" binding:"required"` 16 | } 17 | -------------------------------------------------------------------------------- /pkg/handler/earn/interface.go: -------------------------------------------------------------------------------- 1 | package earn 2 | 3 | import "github.com/gin-gonic/gin" 4 | 5 | type IHandler interface { 6 | ListEarn(c *gin.Context) 7 | } 8 | -------------------------------------------------------------------------------- /pkg/handler/employee/testdata/create/existed_user.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "team email already exists" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/employee/testdata/create/invalid_uuid.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "position not found" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/employee/testdata/create/validation_err.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "Key: 'CreateEmployeeRequest.PersonalEmail' Error:Field validation for 'PersonalEmail' failed on the 'email' tag", 4 | "errors": [ 5 | { 6 | "field": "PersonalEmail", 7 | "msg": "Field validation for 'PersonalEmail' failed on the 'email' tag" 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /pkg/handler/employee/testdata/get_line_managers/200_ok.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "id": "2655832e-f009-4b73-a535-64c3a22e558f", 5 | "fullName": "Phạm Đức Thành", 6 | "displayName": "Thanh Pham", 7 | "avatar": "https://s3-ap-southeast-1.amazonaws.com/fortress-images/5153574695663955944.png", 8 | "username": "thanh" 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /pkg/handler/employee/testdata/list/invalid_chapter_code.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid chapter code" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/employee/testdata/list/invalid_organization_code.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid organization code" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/employee/testdata/list/invalid_position_code.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid position code" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/employee/testdata/list/invalid_project_code.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid project code" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/employee/testdata/list/invalid_seniority_code.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid seniority code" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/employee/testdata/list/invalid_stack_code.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid stack code" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/employee/testdata/list/out_of_content.json: -------------------------------------------------------------------------------- 1 | { 2 | "page": 5, 3 | "size": 5, 4 | "sort": "", 5 | "total": 2, 6 | "data": [] 7 | } 8 | -------------------------------------------------------------------------------- /pkg/handler/employee/testdata/one/404.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "employee not found" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/employee/testdata/update_employee_status/400.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid employee ID" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/employee/testdata/update_employee_status/404.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "employee not found" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/employee/testdata/update_employee_status/invalid_employee_status.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid value for employee status" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/employee/testdata/update_general_info/200.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": { 3 | "id": "2655832e-f009-4b73-a535-64c3a22e558f", 4 | "createdAt": "2022-11-02T09:52:34.586566Z", 5 | "updatedAt": "", 6 | "fullName": "Phạm Đức Thành", 7 | "teamEmail": "thanh@d.foundation", 8 | "phoneNumber": "0123456788", 9 | "githubID": "", 10 | "notionID": "", 11 | "notionName": "", 12 | "notionEmail": "", 13 | "discordID": "", 14 | "discordName": "", 15 | "lineManager": null, 16 | "displayName": "new", 17 | "linkedInName": "", 18 | "referredBy": null, 19 | "organizations": [] 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /pkg/handler/employee/testdata/update_general_info/400.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid employee ID" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/employee/testdata/update_general_info/404.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "employee not found" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/employee/testdata/update_general_info/invalid_join_date.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid joined date" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/employee/testdata/update_general_info/line_manager_not_found.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "line manager not found" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/employee/testdata/update_general_info/organization_not_found.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "organization not found" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/employee/testdata/update_personal_info/200.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": { 3 | "id": "", 4 | "createdAt": "", 5 | "updatedAt": "", 6 | "personalEmail": "thanhpham124@gmail.com", 7 | "address": "Phan Huy Ich, Tan Binh District, Ho Chi Minh, Vietnam", 8 | "placeOfResidence": "", 9 | "gender": "Male", 10 | "birthday": "1990-01-02T00:00:00Z", 11 | "country": "Vietnam", 12 | "city": "Hồ Chí Minh" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /pkg/handler/employee/testdata/update_personal_info/400.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid employee ID" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/employee/testdata/update_personal_info/404.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "employee not found" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/employee/testdata/update_personal_info/invalid_country.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "city does not belong to country" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/employee/testdata/update_role/200.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "message": "ok" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/employee/testdata/update_role/404.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "employee not found" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/employee/testdata/update_role/404_role.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "role not found" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/employee/testdata/update_skills/400.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid employee ID" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/employee/testdata/update_skills/404.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "employee not found" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/employee/testdata/update_skills/stack_not_found.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "stack not found" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/engagement/errors.go: -------------------------------------------------------------------------------- 1 | package engagement 2 | -------------------------------------------------------------------------------- /pkg/handler/engagement/interface.go: -------------------------------------------------------------------------------- 1 | package engagement 2 | 3 | import "github.com/gin-gonic/gin" 4 | 5 | type IHandler interface { 6 | UpsertRollup(c *gin.Context) 7 | GetLastMessageID(c *gin.Context) 8 | IndexMessages(c *gin.Context) 9 | } 10 | -------------------------------------------------------------------------------- /pkg/handler/feedback/interface.go: -------------------------------------------------------------------------------- 1 | package feedback 2 | 3 | import "github.com/gin-gonic/gin" 4 | 5 | type IHandler interface { 6 | List(c *gin.Context) 7 | Detail(c *gin.Context) 8 | Submit(c *gin.Context) 9 | CountUnreadFeedback(c *gin.Context) 10 | } 11 | -------------------------------------------------------------------------------- /pkg/handler/feedback/testdata/detail/404.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "topic not found" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/feedback/testdata/get_unread_inbox/200_happy_case.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": { 3 | "reviewerID":"2655832e-f009-4b73-a535-64c3a22e558f", 4 | "count": 2 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /pkg/handler/feedback/testdata/list/invalid_status.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid reviewer status" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/feedback/testdata/submit/400_unanswer_question.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "must answer all questions" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/feedback/testdata/submit/404.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "topic not found" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/healthz/healthz.go: -------------------------------------------------------------------------------- 1 | package healthz 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/gin-gonic/gin" 7 | ) 8 | 9 | type handler struct{} 10 | 11 | func New() IHandler { 12 | return &handler{} 13 | } 14 | 15 | // Healthz handler 16 | // Return "OK" 17 | func (h *handler) Healthz(c *gin.Context) { 18 | c.Header("Content-Type", "text/plain") 19 | c.String(http.StatusOK, "OK") 20 | } 21 | -------------------------------------------------------------------------------- /pkg/handler/healthz/interface.go: -------------------------------------------------------------------------------- 1 | package healthz 2 | 3 | import "github.com/gin-gonic/gin" 4 | 5 | type IHandler interface { 6 | Healthz(c *gin.Context) 7 | } 8 | -------------------------------------------------------------------------------- /pkg/handler/icy/interface.go: -------------------------------------------------------------------------------- 1 | package icy 2 | 3 | import "github.com/gin-gonic/gin" 4 | 5 | type IHandler interface { 6 | Accounting(c *gin.Context) 7 | } 8 | -------------------------------------------------------------------------------- /pkg/handler/invoice/interface.go: -------------------------------------------------------------------------------- 1 | package invoice 2 | 3 | import "github.com/gin-gonic/gin" 4 | 5 | type IHandler interface { 6 | GetTemplate(c *gin.Context) 7 | List(c *gin.Context) 8 | Send(c *gin.Context) 9 | UpdateStatus(c *gin.Context) 10 | CalculateCommissions(c *gin.Context) 11 | } 12 | -------------------------------------------------------------------------------- /pkg/handler/invoice/testdata/create/400.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid email domain" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/invoice/testdata/create/404.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "bank account not found" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/invoice/testdata/update_status/200.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "message": "ok" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/invoice/testdata/update_status/400_invalid_status.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid invoice status" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/invoice/testdata/update_status/404.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invoice not found" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/memologs/errs/errors.go: -------------------------------------------------------------------------------- 1 | package errs 2 | 3 | import "errors" 4 | 5 | var ( 6 | ErrInvalidPublishedAt = errors.New("cannot parse publishedAt") 7 | ErrInvalidDateFormat = errors.New("invalid date format") 8 | ) 9 | -------------------------------------------------------------------------------- /pkg/handler/memologs/interface.go: -------------------------------------------------------------------------------- 1 | package memologs 2 | 3 | import "github.com/gin-gonic/gin" 4 | 5 | type IHandler interface { 6 | Create(c *gin.Context) 7 | List(c *gin.Context) 8 | Sync(c *gin.Context) 9 | ListOpenPullRequest(c *gin.Context) 10 | ListByDiscordID(c *gin.Context) 11 | GetTopAuthors(c *gin.Context) 12 | } 13 | -------------------------------------------------------------------------------- /pkg/handler/memologs/request/request.go: -------------------------------------------------------------------------------- 1 | package request 2 | 3 | import ( 4 | "github.com/shopspring/decimal" 5 | ) 6 | 7 | type CreateMemoLogsRequest []MemoLogItem // @name CreateMemoLogsRequest 8 | 9 | type MemoLogItem struct { 10 | Title string `json:"title" binding:"required"` 11 | URL string `json:"url" binding:"required"` 12 | Authors []string `json:"authors"` 13 | Tags []string `json:"tags"` 14 | Description string `json:"description"` 15 | PublishedAt string `json:"publishedAt"` 16 | Reward decimal.Decimal `json:"reward"` 17 | } 18 | -------------------------------------------------------------------------------- /pkg/handler/metadata/errors.go: -------------------------------------------------------------------------------- 1 | package metadata 2 | 3 | import "errors" 4 | 5 | var ( 6 | ErrInvalidCategory = errors.New("invalid category") 7 | ErrInvalidSubcategory = errors.New("invalid subcategory") 8 | ) 9 | -------------------------------------------------------------------------------- /pkg/handler/metadata/errs/errs.go: -------------------------------------------------------------------------------- 1 | package errs 2 | 3 | import "errors" 4 | 5 | var ( 6 | ErrInvalidStackID = errors.New("invalid stack ID") 7 | ErrStackNotFound = errors.New("stack not found") 8 | ErrInvalidPositionID = errors.New("invalid Position ID") 9 | ErrPositionNotFound = errors.New("position not found") 10 | ErrEmployeeNotFound = errors.New("employee not found") 11 | ) 12 | -------------------------------------------------------------------------------- /pkg/handler/metadata/testdata/create_position/200.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "message": "ok" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/metadata/testdata/create_stack/200.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "message": "ok" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/metadata/testdata/delete_position/200.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "message": "ok" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/metadata/testdata/delete_stack/200.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "message": "ok" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/metadata/testdata/get_account_roles/200.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "id": "11ccffea-2cc9-4e98-9bef-3464dfe4dec8", 5 | "createdAt": "2022-11-07T09:50:25.714604Z", 6 | "updatedAt": "2022-11-07T09:50:25.714604Z", 7 | "name": "⚪️ Admin", 8 | "code": "admin", 9 | "level": 1 10 | }, 11 | { 12 | "id": "d796884d-a8c4-4525-81e7-54a3b6099eac", 13 | "createdAt": "2022-11-07T09:50:25.714604Z", 14 | "updatedAt": "2022-11-07T09:50:25.714604Z", 15 | "name": "⚪️ Member", 16 | "code": "member", 17 | "level": 2 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /pkg/handler/metadata/testdata/get_project_statuses/200.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "id": "", 5 | "code": "on-boarding", 6 | "name": "On Boarding" 7 | }, 8 | { 9 | "id": "", 10 | "code": "paused", 11 | "name": "Paused" 12 | }, 13 | { 14 | "id": "", 15 | "code": "active", 16 | "name": "Active" 17 | }, 18 | { 19 | "id": "", 20 | "code": "closed", 21 | "name": "Closed" 22 | } 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /pkg/handler/metadata/testdata/get_questions/400.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid subcategory" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/metadata/testdata/get_working_status/200.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "id": "", 5 | "code": "left", 6 | "name": "Left" 7 | }, 8 | { 9 | "id": "", 10 | "code": "on-boarding", 11 | "name": "On Boarding" 12 | }, 13 | { 14 | "id": "", 15 | "code": "probation", 16 | "name": "Probation" 17 | }, 18 | { 19 | "id": "", 20 | "code": "full-time", 21 | "name": "Full-time" 22 | }, 23 | { 24 | "id": "", 25 | "code": "contractor", 26 | "name": "Contractor" 27 | } 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /pkg/handler/metadata/testdata/update_position/200.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "message": "ok" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/metadata/testdata/update_position/404.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "position not found" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/metadata/testdata/update_stack/200.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "message": "ok" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/metadata/testdata/update_stack/404.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "stack not found" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/news/interface.go: -------------------------------------------------------------------------------- 1 | package news 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | ) 6 | 7 | type IHandler interface { 8 | Fetch(c *gin.Context) 9 | } 10 | -------------------------------------------------------------------------------- /pkg/handler/payroll/errs/errors.go: -------------------------------------------------------------------------------- 1 | package errs 2 | 3 | import "errors" 4 | 5 | var ( 6 | ErrBadRequest = errors.New("bad request") 7 | ErrInvalidYear = errors.New("invalid year, must be current year") 8 | ErrCannotReadProjectBonusExplain = errors.New("cannot read project bonus explain") 9 | ErrPayrollNotSnapshotted = errors.New("payroll not snapshotted") 10 | ) 11 | -------------------------------------------------------------------------------- /pkg/handler/profile/interface.go: -------------------------------------------------------------------------------- 1 | package profile 2 | 3 | import "github.com/gin-gonic/gin" 4 | 5 | type IHandler interface { 6 | GetProfile(c *gin.Context) 7 | UpdateInfo(c *gin.Context) 8 | SubmitOnboardingForm(c *gin.Context) 9 | GetInvitation(c *gin.Context) 10 | Upload(c *gin.Context) 11 | UploadAvatar(c *gin.Context) 12 | } 13 | -------------------------------------------------------------------------------- /pkg/handler/profile/testdata/update_info/400.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "Key: 'UpdateInfoInput.PhoneNumber' Error:Field validation for 'PhoneNumber' failed on the 'min' tag", 4 | "errors": [ 5 | { 6 | "field": "PhoneNumber", 7 | "msg": "Field validation for 'PhoneNumber' failed on the 'min' tag" 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/archive_work_unit/200_ok.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "message": "ok" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/archive_work_unit/404_project_not_found.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "project not found" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/archive_work_unit/invalid_project_id.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid project ID" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/archive_work_unit/invalid_work_unit_id.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid work unit ID" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/assign_member/404_project_not_found.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "project not found" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/assign_member/invalid_project_id.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid project ID" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/create/400_duplicate_slug.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "project code is duplicated" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/create/400_invalid_deployment_type.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid deployment type" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/create/400_invalid_email.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid email domain for client" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/create/400_invalid_end_date_member.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid end date" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/create/400_invalid_function.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid project function value" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/create/400_invalid_startDate.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "parsing time \"2022-15-02\": month out of range" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/create/400_invalid_start_date_member.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid start date" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/create/400_invalid_status.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid project status" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/create/400_invalid_type.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid project type" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/create/400_missing_account_manager.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "account manager is required" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/create/400_misssing_name.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "Key: 'CreateProjectInput.Name' Error:Field validation for 'Name' failed on the 'required' tag", 4 | "errors": [ 5 | { 6 | "field": "Name", 7 | "msg": "Field validation for 'Name' failed on the 'required' tag" 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/create/400_misssing_status.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "Key: 'CreateProjectRequest.Status' Error:Field validation for 'Status' failed on the 'required' tag", 4 | "errors": [ 5 | { 6 | "field": "Status", 7 | "msg": "Field validation for 'Status' failed on the 'required' tag" 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/create/400_project_member_status.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid project member status" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/create/400_project_position_empty.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "positions is empty" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/create_work_unit/404_project_not_found.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "project not found" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/create_work_unit/invalid_project_id.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid project ID" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/create_work_unit/invalid_work_unit_stack.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid work unit stacks" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/create_work_unit/invalid_work_unit_status.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid work unit status" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/create_work_unit/invalid_work_unit_type.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid work unit type" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/delete_member/200.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "message": "ok" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/delete_member/404.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "project member not found" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/delete_member/empty_member_id.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid member ID" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/delete_member/empty_project_id.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid project ID" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/delete_member/project_not_found.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "project member not found" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/delete_slot/200.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "message": "ok" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/delete_slot/404.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "project slot not found" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/delete_slot/empty_project_id.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid project ID" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/delete_slot/empty_slot_id.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid slot ID" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/delete_slot/project_not_found.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "project not found" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/get_list_work_unit/400.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid work unit status" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/get_list_work_unit/404.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "project not found" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/get_list_work_unit/invalid_project_id.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid project ID" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/get_members/invalid_project_id.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid project ID" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/get_members/invalid_project_member_status.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid project member status" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/get_members/project_not_found.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "project not found" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/get_project/404.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "project not found" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/get_project/invalid_project_id.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid project ID" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/get_projects/invalid_project_status.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid project status" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/get_projects/invalid_project_type.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid project type" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/unarchive_work_unit/200_ok.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "message": "ok" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/unarchive_work_unit/404_project_not_found.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "project not found" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/unarchive_work_unit/invalid_project_id.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid project ID" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/unarchive_work_unit/invalid_work_unit_id.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid work unit ID" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/unassign_member/200.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "message": "ok" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/unassign_member/404.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "project member not found" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/unassign_member/empty_member_id.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid member ID" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/unassign_member/empty_project_id.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid project ID" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/unassign_member/project_not_found.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "project member not found" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/update_contact_info/404.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "project not found" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/update_contact_info/account_manager_not_found.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "employee not found" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/update_contact_info/delivery_manager_not_found.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "employee not found" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/update_contact_info/invalid_email_format.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid email domain for client" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/update_contact_info/invalid_project_id.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid project ID" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/update_general_info/404.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "project not found" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/update_general_info/country_not_found.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "country not found" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/update_general_info/invalid_project_function.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid project function value" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/update_general_info/invalid_project_id.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid project ID" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/update_general_info/stack_not_found.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "stack not found: fa0f4e46-7eab-4e5c-9d31-30489e69fe2d" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/update_member/400_invalid_start_date.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid start date" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/update_member/404_project_not_found.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "project not found" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/update_member/invalid_deployment_type.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid deployment type" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/update_member/invalid_project_id.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid project ID" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/update_member/invalid_status.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid project member status" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/update_member/position_not_found.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "position not found: 11ccffea-2cc9-4e98-9bef-3464dfe4dec9" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/update_member/project_slot_not_found.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "project slot not found" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/update_member/seniority_not_found.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "seniority not found" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/update_project_status/200.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": { 3 | "id": "8dc3be2e-19a4-4942-8a79-56db391a0b15", 4 | "createdAt": "2022-11-11T18:06:56.362902Z", 5 | "updatedAt": "", 6 | "name": "Fortress", 7 | "type": "dwarves", 8 | "status": "active", 9 | "startDate": "2022-11-01T00:00:00Z", 10 | "endDate": null 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/update_project_status/400.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid project status" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/update_project_status/404.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "project not found" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/update_project_status/invalid_project_id.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid project ID" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/update_sending_survey/200.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "message": "ok" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/update_sending_survey/404.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "project not found" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/update_sending_survey/invalid_project_id.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid project ID" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/update_work_unit/200.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "message": "ok" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/update_work_unit/400.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid work unit type" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/update_work_unit/404.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "project not found" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/update_work_unit/invalid_project_id.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid project ID" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/update_work_unit/invalid_stack.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid work unit stacks" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/project/testdata/update_work_unit/stack_not_found.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "stack not found: fa0f4e46-7eab-4e5c-9d31-30489e69fe2d" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/survey/interface.go: -------------------------------------------------------------------------------- 1 | package survey 2 | 3 | import "github.com/gin-gonic/gin" 4 | 5 | type IHandler interface { 6 | ListSurvey(c *gin.Context) 7 | GetSurveyDetail(c *gin.Context) 8 | GetSurveyReviewDetail(c *gin.Context) 9 | SendSurvey(c *gin.Context) 10 | CreateSurvey(c *gin.Context) 11 | DeleteSurvey(c *gin.Context) 12 | DeleteSurveyTopic(c *gin.Context) 13 | GetSurveyTopicDetail(c *gin.Context) 14 | UpdateTopicReviewers(c *gin.Context) 15 | MarkDone(c *gin.Context) 16 | DeleteTopicReviewers(c *gin.Context) 17 | } 18 | -------------------------------------------------------------------------------- /pkg/handler/survey/testdata/create_survey/200_work.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "message": "ok" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/survey/testdata/create_survey/400.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid date range" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/survey/testdata/create_survey/invalid_date.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid date" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/survey/testdata/create_survey/invalid_subtype.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid event subtype" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/survey/testdata/delete_survey/200_valid_id.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "message": "ok" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/survey/testdata/delete_survey/404_event_not_found.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "event not found" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/survey/testdata/delete_survey/invalid_event_id.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid event id" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/survey/testdata/delete_survey/invalid_topic_id.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid topic id" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/survey/testdata/delete_survey/topic_not_found.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "topic not found" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/survey/testdata/delete_topic_participants/200.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "message": "ok" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/survey/testdata/delete_topic_participants/404.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "employee event reviewer not found" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/survey/testdata/get_peer_review_detail/404.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "topic not found" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/survey/testdata/get_peer_review_detail/invalid_feedback_id.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid feedback id" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/survey/testdata/get_peer_review_detail/invalid_topic_id.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid topic id" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/survey/testdata/get_peer_review_detail/topic_not_found.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "topic not found" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/survey/testdata/get_survey_detail/404_event_id_not_found.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "event not found" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/survey/testdata/get_survey_detail/invalid_event_id.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid event id" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/survey/testdata/get_survey_review_detail/404_not_found.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "topic not found" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/survey/testdata/get_survey_review_detail/invalid_event_id.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid event id" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/survey/testdata/get_survey_review_detail/invalid_review_id.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid reviewer id" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/survey/testdata/get_survey_review_detail/invalid_topic_id.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid topic id" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/survey/testdata/list_survey/200_get_peer_review.json: -------------------------------------------------------------------------------- 1 | { 2 | "page": 0, 3 | "size": 999, 4 | "sort": "", 5 | "total": 1, 6 | "data": [ 7 | { 8 | "id": "8a5bfedb-6e11-4f5c-82d9-2635cfcce3e2", 9 | "title": "Q3/Q4, 2022", 10 | "type": "survey", 11 | "subtype": "peer-review", 12 | "status": "in-progress", 13 | "startDate": "2022-11-29T08:03:33.233262Z", 14 | "endDate": "2023-05-29T08:03:33.233262Z", 15 | "count": { 16 | "total": 1, 17 | "sent": 0, 18 | "done": 0 19 | }, 20 | "domains": null 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /pkg/handler/survey/testdata/list_survey/400_empty_query.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "Key: 'GetListSurveyInput.Subtype' Error:Field validation for 'Subtype' failed on the 'required' tag", 4 | "errors": [ 5 | { 6 | "field": "Subtype", 7 | "msg": "Field validation for 'Subtype' failed on the 'required' tag" 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /pkg/handler/survey/testdata/mark_done/200.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "message": "ok" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/survey/testdata/mark_done/400.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "all reviewers have to finish before marked done" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/survey/testdata/mark_done/404.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "event not found" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/survey/testdata/mark_done/invalid_event_id.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid event id" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/survey/testdata/send_survey/200_performance_review.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "message": "ok" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/survey/testdata/send_survey/200_send_engagement.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "message": "ok" 4 | } 5 | 6 | -------------------------------------------------------------------------------- /pkg/handler/survey/testdata/send_survey/404.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "event not found" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/survey/testdata/send_survey/invalid_event_id.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid event id" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/survey/testdata/send_survey/invalid_subtype.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid event subtype" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/survey/testdata/update_topic_participants/200_happy_case.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "message": "ok" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/survey/testdata/update_topic_participants/400_participant_not_ready.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "employee not ready" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/survey/testdata/update_topic_participants/invalid_event_id.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid event id" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/survey/testdata/update_topic_participants/invalid_topic_id.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": null, 3 | "error": "invalid topic id" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/handler/valuation/interface.go: -------------------------------------------------------------------------------- 1 | package valuation 2 | 3 | import "github.com/gin-gonic/gin" 4 | 5 | type IHandler interface { 6 | One(c *gin.Context) 7 | } 8 | -------------------------------------------------------------------------------- /pkg/handler/vault/interface.go: -------------------------------------------------------------------------------- 1 | package vault 2 | 3 | import "github.com/gin-gonic/gin" 4 | 5 | type IHandler interface { 6 | StoreVaultTransaction(c *gin.Context) 7 | } 8 | -------------------------------------------------------------------------------- /pkg/handler/webhook/constant.go: -------------------------------------------------------------------------------- 1 | package webhook 2 | 3 | const ( 4 | KindGcalEvent = "google#calendar#event" 5 | ) 6 | -------------------------------------------------------------------------------- /pkg/handler/webhook/interface.go: -------------------------------------------------------------------------------- 1 | package webhook 2 | 3 | import "github.com/gin-gonic/gin" 4 | 5 | type IHandler interface { 6 | N8n(c *gin.Context) 7 | CreateBasecampExpense(c *gin.Context) 8 | MarkInvoiceAsPaidViaBasecamp(c *gin.Context) 9 | StoreAccountingTransaction(c *gin.Context) 10 | UncheckBasecampExpense(c *gin.Context) 11 | ValidateBasecampExpense(c *gin.Context) 12 | ValidateOnLeaveRequest(c *gin.Context) 13 | ApproveOnLeaveRequest(c *gin.Context) 14 | } 15 | -------------------------------------------------------------------------------- /pkg/handler/youtube/file.go: -------------------------------------------------------------------------------- 1 | package youtube 2 | 3 | import ( 4 | "os" 5 | ) 6 | 7 | func (h *handler) createFile(path, fileName, content string) error { 8 | if _, err := os.Stat(path); os.IsNotExist(err) { 9 | if err := os.MkdirAll(path, os.ModePerm); err != nil { 10 | return err 11 | } 12 | } 13 | 14 | newFile := path + "/" + fileName 15 | file, err := os.Create(newFile) 16 | if err != nil { 17 | return err 18 | } 19 | defer file.Close() 20 | 21 | _, err = file.WriteString(content) 22 | return err 23 | } 24 | -------------------------------------------------------------------------------- /pkg/handler/youtube/interface.go: -------------------------------------------------------------------------------- 1 | package youtube 2 | 3 | import "github.com/gin-gonic/gin" 4 | 5 | type IHandler interface { 6 | LatestBroadcast(c *gin.Context) 7 | TranscribeBroadcast(c *gin.Context) 8 | } 9 | -------------------------------------------------------------------------------- /pkg/logger/logger.go: -------------------------------------------------------------------------------- 1 | package logger 2 | 3 | type Fields map[string]interface{} 4 | 5 | type Logger interface { 6 | Fields(data Fields) Logger 7 | Field(key, value string) Logger 8 | AddField(key string, value any) Logger 9 | Debug(msg string) 10 | Debugf(msg string, args ...interface{}) 11 | Info(msg string) 12 | Infof(msg string, args ...interface{}) 13 | Warn(msg string) 14 | Warnf(msg string, args ...interface{}) 15 | Error(err error, msg string) 16 | Errorf(err error, msg string, args ...interface{}) 17 | Fatal(err error, msg string) 18 | Fatalf(err error, msg string, args ...interface{}) 19 | } 20 | -------------------------------------------------------------------------------- /pkg/model/action_item_snapshot.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type ActionItemSnapshot struct { 4 | BaseModel 5 | 6 | ProjectID UUID 7 | AuditCycleID UUID 8 | High int64 9 | Medium int64 10 | Low int64 11 | } 12 | 13 | func CompareActionItemSnapshot(old, new *ActionItemSnapshot) bool { 14 | return old.High == new.High && 15 | old.Medium == new.Medium && 16 | old.Low == new.Low 17 | } 18 | -------------------------------------------------------------------------------- /pkg/model/answer.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | // Answer model for answers table 4 | type Answer struct { 5 | BaseModel 6 | 7 | QuestionID UUID 8 | AnswerBy UUID 9 | Answer string 10 | Note string 11 | } 12 | -------------------------------------------------------------------------------- /pkg/model/answer_drafts.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | // AnswerDraft model for answer_drafts table 4 | type AnswerDraft struct { 5 | BaseModel 6 | 7 | QuestionID UUID 8 | AnswerBy UUID 9 | Answer string 10 | Note string 11 | } 12 | -------------------------------------------------------------------------------- /pkg/model/api_key_roles.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type APIKeyRole struct { 4 | BaseModel 5 | 6 | APIKeyID UUID `gorm:"column:api_key_id;default:null"` 7 | RoleID UUID 8 | 9 | ApiKey APIKey 10 | Role Role 11 | } 12 | -------------------------------------------------------------------------------- /pkg/model/asset.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import "time" 4 | 5 | type Asset struct { 6 | BaseModel 7 | 8 | Name string 9 | Price int64 10 | Quantity string 11 | Note string 12 | Location string 13 | PurchaseDate *time.Time 14 | } 15 | -------------------------------------------------------------------------------- /pkg/model/audit_action_item.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type AuditActionItem struct { 4 | BaseModel 5 | 6 | AuditID UUID 7 | ActionItemID UUID 8 | } 9 | 10 | type AuditAction struct { 11 | AuditID UUID 12 | ActionItemID UUID 13 | } 14 | 15 | func AuditActionItemToMap(aais []*AuditActionItem) map[AuditAction]AuditActionItem { 16 | rs := make(map[AuditAction]AuditActionItem) 17 | for _, aai := range aais { 18 | rs[AuditAction{AuditID: aai.AuditID, ActionItemID: aai.ActionItemID}] = *aai 19 | } 20 | 21 | return rs 22 | } 23 | -------------------------------------------------------------------------------- /pkg/model/audit_participants.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type AuditParticipant struct { 4 | BaseModel 5 | 6 | AuditID UUID 7 | EmployeeID UUID 8 | } 9 | 10 | func AuditParticipantToMap(auditParticipant []*AuditParticipant) map[UUID]AuditParticipant { 11 | rs := make(map[UUID]AuditParticipant) 12 | for _, ap := range auditParticipant { 13 | rs[ap.EmployeeID] = *ap 14 | } 15 | 16 | return rs 17 | } 18 | -------------------------------------------------------------------------------- /pkg/model/auth.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "github.com/golang-jwt/jwt/v4" 5 | ) 6 | 7 | // AuthenticationInfo .. 8 | type AuthenticationInfo struct { 9 | jwt.StandardClaims 10 | 11 | UserID string `json:"id"` 12 | Avatar string `json:"avatar"` 13 | Email string `json:"email"` 14 | } 15 | 16 | type CurrentLoggedUserInfo struct { 17 | UserID string 18 | Permissions map[string]string 19 | Projects map[UUID]*Project 20 | Role string 21 | } 22 | -------------------------------------------------------------------------------- /pkg/model/bank_account.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | // BankAccount contain company information 4 | type BankAccount struct { 5 | BaseModel 6 | 7 | AccountNumber string 8 | BankName string 9 | OwnerName string 10 | Address *string 11 | SwiftCode string 12 | RoutingNumber string 13 | Name string 14 | UKSortCode string 15 | IntermediaryBankName string 16 | IntermediaryBankAddress string 17 | 18 | CurrencyID UUID 19 | Currency *Currency 20 | } 21 | -------------------------------------------------------------------------------- /pkg/model/banks.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type Bank struct { 4 | BaseModel 5 | 6 | Name string 7 | Code string 8 | Bin string 9 | ShortName string 10 | Logo string 11 | SwiftCode string 12 | } 13 | -------------------------------------------------------------------------------- /pkg/model/brainery_log.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/shopspring/decimal" 7 | ) 8 | 9 | type BraineryLog struct { 10 | BaseModel 11 | 12 | Title string 13 | URL string 14 | GithubID string 15 | DiscordID string 16 | EmployeeID UUID 17 | Tags JSONArrayString 18 | PublishedAt *time.Time 19 | Reward decimal.Decimal 20 | } 21 | -------------------------------------------------------------------------------- /pkg/model/cached_payroll.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "gorm.io/datatypes" 5 | "gorm.io/gorm" 6 | ) 7 | 8 | type CachedPayroll struct { 9 | ID UUID `sql:",type:uuid" json:"id"` 10 | Month int `json:"month"` 11 | Year int `json:"year"` 12 | Batch int `json:"batch"` 13 | Payrolls datatypes.JSON `json:"payrolls"` 14 | } 15 | 16 | func (p *CachedPayroll) BeforeCreate(scope *gorm.DB) error { 17 | p.ID = NewUUID() 18 | return nil 19 | } 20 | 21 | func (CachedPayroll) TableName() string { return "cached_payrolls" } 22 | -------------------------------------------------------------------------------- /pkg/model/chapters.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type Chapter struct { 4 | BaseModel 5 | 6 | Name string `json:"name"` 7 | Code string `json:"code"` 8 | LeadID *UUID `json:"lead_id"` 9 | } 10 | 11 | // ToChapterMap create map from chapters 12 | func ToChapterMap(chapters []*Chapter) map[UUID]string { 13 | rs := map[UUID]string{} 14 | for _, s := range chapters { 15 | rs[s.ID] = s.Name 16 | } 17 | 18 | return rs 19 | } 20 | -------------------------------------------------------------------------------- /pkg/model/client.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | // Client store information of a Client 4 | type Client struct { 5 | BaseModel 6 | 7 | Name string 8 | Description string 9 | RegistrationNumber string 10 | Avatar string 11 | Address string 12 | Country string 13 | City string 14 | Industry string 15 | Website string 16 | IsPublic bool 17 | Lat string 18 | Long string 19 | CompanySize string 20 | SolutionType string 21 | 22 | Contacts []ClientContact 23 | Projects []Project 24 | } 25 | -------------------------------------------------------------------------------- /pkg/model/client_contact.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "gorm.io/datatypes" 5 | ) 6 | 7 | // ClientContact is the model for the client_contact table 8 | type ClientContact struct { 9 | BaseModel 10 | 11 | Name string 12 | ClientID UUID 13 | Role string 14 | Emails datatypes.JSON 15 | IsMainContact bool 16 | } 17 | 18 | type ClientEmail struct { 19 | Emails []string `json:"emails"` 20 | } 21 | -------------------------------------------------------------------------------- /pkg/model/commission.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import "github.com/shopspring/decimal" 4 | 5 | type CommissionModel struct { 6 | Beneficiary BasicEmployeeInfo 7 | CommissionType string 8 | CommissionRate decimal.Decimal 9 | Description string 10 | Sub *CommissionModel 11 | } 12 | 13 | type BasicEmployeeInfo struct { 14 | ID string 15 | FullName string 16 | DisplayName string 17 | Avatar string 18 | Username string 19 | ReferredBy string 20 | } 21 | -------------------------------------------------------------------------------- /pkg/model/communitynft.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | // Client store information of a Client 4 | type NftMetadata struct { 5 | Name string 6 | Description string 7 | Image string 8 | BackgroundColor string 9 | Attributes []NftAttribute 10 | } 11 | 12 | type NftAttribute struct { 13 | TraitType string 14 | Value string 15 | } 16 | -------------------------------------------------------------------------------- /pkg/model/company_info.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import "github.com/jackc/pgtype" 4 | 5 | // CompanyInfo contain company information 6 | type CompanyInfo struct { 7 | BaseModel 8 | 9 | Name string `json:"name"` 10 | Description string `json:"description"` 11 | RegistrationNumber string `json:"registrationNumber"` 12 | Info pgtype.JSONB `json:"info"` 13 | } 14 | 15 | type CompanyContactInfo struct { 16 | Address string `json:"address"` 17 | Phone string `json:"phone"` 18 | } 19 | -------------------------------------------------------------------------------- /pkg/model/config.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | const ( 4 | ConfigKeySalaryAdvanceMaxCap = "salary-advance-max-cap" 5 | ConfigKeyIcyUSDRate = "icy-usd-rate" 6 | ) 7 | 8 | type Config struct { 9 | BaseModel `json:"base_model"` 10 | 11 | Key string `json:"key"` 12 | Value string `json:"value"` 13 | } 14 | 15 | func (Config) TableName() string { return "configs" } 16 | -------------------------------------------------------------------------------- /pkg/model/conversion_rate.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import "github.com/shopspring/decimal" 4 | 5 | type ConversionRate struct { 6 | BaseModel 7 | 8 | CurrencyID UUID 9 | Currency Currency 10 | ToUSD decimal.Decimal 11 | ToVND decimal.Decimal 12 | } 13 | -------------------------------------------------------------------------------- /pkg/model/date_time.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import "time" 4 | 5 | type DateTime struct { 6 | Time time.Time `json:"time"` 7 | HasTime bool `json:"has_time"` 8 | } 9 | -------------------------------------------------------------------------------- /pkg/model/discord.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type LogDiscordInput struct { 4 | Type string 5 | Data interface{} 6 | } 7 | 8 | type DiscordLogTemplate struct { 9 | ID string `json:"id"` 10 | Description string 11 | Content string 12 | } 13 | 14 | type DiscordRole string 15 | 16 | func (r DiscordRole) String() string { 17 | return string(r) 18 | } 19 | 20 | const ( 21 | DiscordRolePeeps DiscordRole = "peeps" 22 | ) 23 | -------------------------------------------------------------------------------- /pkg/model/discord_account.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import "github.com/lib/pq" 4 | 5 | type DiscordAccount struct { 6 | BaseModel 7 | 8 | DiscordID string 9 | DiscordUsername string `json:"discord_username"` 10 | MemoUsername string `json:"memo_username"` 11 | Roles pq.StringArray `json:"role" gorm:"type:text[]"` 12 | GithubUsername string `json:"github_username"` 13 | PersonalEmail string `json:"personal_email"` 14 | 15 | Employee *Employee `json:"employee"` 16 | } 17 | -------------------------------------------------------------------------------- /pkg/model/dynamic_events.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "encoding/json" 5 | "time" 6 | ) 7 | 8 | // DynamicEvent represents the event to be stored in parquet format 9 | type DynamicEvent struct { 10 | Data json.RawMessage `parquet:"name=data, type=BYTE_ARRAY, convertedtype=UTF8"` 11 | EventType string `parquet:"name=event_type, type=BYTE_ARRAY, convertedtype=UTF8"` 12 | Timestamp time.Time `parquet:"name=timestamp, type=INT96"` 13 | } 14 | -------------------------------------------------------------------------------- /pkg/model/earn.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type Earn struct { 4 | Title string 5 | Bounty string 6 | Status string 7 | PICs []string 8 | Function string 9 | URL string 10 | } 11 | -------------------------------------------------------------------------------- /pkg/model/email.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import "github.com/sendgrid/sendgrid-go/helpers/mail" 4 | 5 | type Email struct { 6 | HTMLContent string 7 | Subject string 8 | From *mail.Email 9 | To []*mail.Email 10 | Bcc []*mail.Email 11 | Categories []string 12 | } 13 | -------------------------------------------------------------------------------- /pkg/model/employee_bonus.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | // EmployeeBonus represents employeeBonus table 4 | // save the commission when invoice is paid for an employee 5 | type EmployeeBonus struct { 6 | ID UUID `json:"id"` 7 | EmployeeID UUID `json:"employee_id"` 8 | Amount VietnamDong `json:"amount"` 9 | IsActive bool `json:"is_active"` 10 | Name string `json:"name"` 11 | } 12 | 13 | func (EmployeeBonus) TableName() string { return "employee_bonuses" } 14 | -------------------------------------------------------------------------------- /pkg/model/employee_chapters.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type EmployeeChapter struct { 4 | BaseModel 5 | 6 | EmployeeID UUID 7 | ChapterID UUID 8 | 9 | Chapter Chapter 10 | } 11 | -------------------------------------------------------------------------------- /pkg/model/employee_earns.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import "github.com/dwarvesf/fortress-api/pkg/service/mochipay" 4 | 5 | type EmployeeEarnTransactions []mochipay.TransactionData 6 | -------------------------------------------------------------------------------- /pkg/model/employee_invitations.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type EmployeeInvitation struct { 4 | BaseModel 5 | 6 | EmployeeID UUID 7 | InvitedBy UUID 8 | InvitationCode string 9 | IsCompleted bool 10 | IsInfoUpdated bool 11 | IsDiscordRoleAssigned bool 12 | IsBasecampAccountCreated bool 13 | IsTeamEmailCreated bool 14 | Employee *Employee 15 | } 16 | 17 | type InvitationEmail struct { 18 | Name string `json:"name"` 19 | Email string `json:"email"` 20 | Link string `json:"link"` 21 | Inviter string `json:"inviter"` 22 | } 23 | -------------------------------------------------------------------------------- /pkg/model/employee_mentees.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | // EmployeeMentee define the model for table employee_mentees 4 | type EmployeeMentee struct { 5 | BaseModel 6 | 7 | MenteeID UUID 8 | MentorID UUID 9 | 10 | Mentee *Employee `gorm:"foreignKey:MenteeID"` 11 | } 12 | -------------------------------------------------------------------------------- /pkg/model/employee_mma_score.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/shopspring/decimal" 7 | ) 8 | 9 | // EmployeeMMAScore define the model for table employee_mma_scores 10 | type EmployeeMMAScore struct { 11 | BaseModel 12 | 13 | EmployeeID UUID 14 | MasteryScore decimal.Decimal 15 | AutonomyScore decimal.Decimal 16 | MeaningScore decimal.Decimal 17 | RatedAt *time.Time 18 | } 19 | 20 | type EmployeeMMAScoreData struct { 21 | EmployeeID UUID 22 | FullName string 23 | MMAID UUID 24 | MasteryScore decimal.Decimal 25 | AutonomyScore decimal.Decimal 26 | MeaningScore decimal.Decimal 27 | RatedAt *time.Time 28 | } 29 | -------------------------------------------------------------------------------- /pkg/model/employee_organizations.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type EmployeeOrganization struct { 4 | BaseModel 5 | 6 | EmployeeID UUID 7 | OrganizationID UUID 8 | 9 | Organization Organization 10 | } 11 | -------------------------------------------------------------------------------- /pkg/model/employee_positions.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type EmployeePosition struct { 4 | BaseModel 5 | 6 | EmployeeID UUID 7 | PositionID UUID 8 | 9 | Position Position 10 | } 11 | -------------------------------------------------------------------------------- /pkg/model/employee_roles.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type EmployeeRole struct { 4 | BaseModel 5 | 6 | EmployeeID UUID 7 | RoleID UUID 8 | 9 | Role Role 10 | } 11 | -------------------------------------------------------------------------------- /pkg/model/employee_stacks.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type EmployeeStack struct { 4 | BaseModel 5 | 6 | EmployeeID UUID 7 | StackID UUID 8 | 9 | Stack Stack 10 | } 11 | -------------------------------------------------------------------------------- /pkg/model/engagement_rollup.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type EngagementsRollup struct { 4 | BaseModel 5 | 6 | DiscordUserID int64 `gorm:"default:null"` 7 | LastMessageID int64 `gorm:"default:null"` 8 | DiscordUsername string `gorm:"default:null"` 9 | ChannelID int64 `gorm:"default:null"` 10 | CategoryID int64 `gorm:"default:null"` 11 | MessageCount int `gorm:"default:null"` 12 | ReactionCount int `gorm:"default:null"` 13 | } 14 | -------------------------------------------------------------------------------- /pkg/model/google_mail.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | // GoogleMailThread -- 4 | type GoogleMailThread struct { 5 | ID string `json:"id"` 6 | Messages []GoogleMailMessage `json:"messages"` 7 | } 8 | 9 | // GoogleMailMessage -- 10 | type GoogleMailMessage struct { 11 | ID string `json:"id"` 12 | ThreadID string `json:"threadId"` 13 | Payload *Payload `json:"payload"` 14 | } 15 | 16 | type Payload struct { 17 | Headers []Header `json:"headers"` 18 | } 19 | 20 | type Header struct { 21 | Name string `json:"name"` 22 | Value string `json:"value"` 23 | } 24 | -------------------------------------------------------------------------------- /pkg/model/icy_distribution.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | // IcyDistribution is a model for icy_distribution table 4 | type IcyDistribution struct { 5 | BaseModel 6 | Team string `json:"team"` 7 | Period string `json:"period"` 8 | Amount string `json:"amount"` 9 | } 10 | -------------------------------------------------------------------------------- /pkg/model/icy_transaction.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | type IcyTransaction struct { 8 | BaseModel 9 | 10 | Category string 11 | TxnTime time.Time 12 | Amount string 13 | Note string 14 | SrcEmployeeID UUID 15 | DestEmployeeID UUID 16 | Sender string 17 | Target string 18 | } 19 | -------------------------------------------------------------------------------- /pkg/model/inbound_fund_transaction.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import "time" 4 | 5 | // InboundFundTransaction records amounts moved to the inbound fund 6 | type InboundFundTransaction struct { 7 | BaseModel 8 | 9 | InvoiceID UUID `json:"invoice_id"` 10 | Amount VietnamDong `json:"amount"` 11 | Notes string `json:"notes"` 12 | ConversionRate float64 13 | PaidAt *time.Time 14 | 15 | Invoice *Invoice `json:"invoice,omitempty"` 16 | } 17 | -------------------------------------------------------------------------------- /pkg/model/liability.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import "time" 4 | 5 | type Liability struct { 6 | BaseModel 7 | 8 | PaidAt *time.Time `json:"paidAt"` 9 | Name string `json:"name"` 10 | Total float64 `json:"total"` 11 | CurrencyID UUID `json:"currencyID"` 12 | } 13 | -------------------------------------------------------------------------------- /pkg/model/memo_author.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "time" 5 | 6 | "gorm.io/gorm" 7 | "gorm.io/gorm/clause" 8 | ) 9 | 10 | // MemoAuthor is the join table for memo log and discord account 11 | type MemoAuthor struct { 12 | MemoLogID UUID `gorm:"primaryKey"` 13 | DiscordAccountID UUID `gorm:"primaryKey"` 14 | CreatedAt time.Time 15 | } 16 | 17 | func (b *MemoAuthor) BeforeCreate(tx *gorm.DB) (err error) { 18 | cols := []clause.Column{} 19 | for _, field := range tx.Statement.Schema.PrimaryFields { 20 | cols = append(cols, clause.Column{Name: field.DBName}) 21 | } 22 | tx.Statement.AddClause(clause.OnConflict{ 23 | Columns: cols, 24 | DoNothing: true, 25 | }) 26 | 27 | return nil 28 | } 29 | -------------------------------------------------------------------------------- /pkg/model/memopr.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | type MemoPullRequest struct { 8 | Number int `json:"number"` 9 | Title string `json:"title"` 10 | DiscordId string `json:"discord_id"` 11 | GithubUserName string `json:"github_user_name"` 12 | Url string `json:"url"` 13 | Timestamp time.Time `json:"timestamp"` 14 | } 15 | -------------------------------------------------------------------------------- /pkg/model/mochi.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type VaultTransaction struct { 4 | ID int64 5 | GuildID string 6 | VaultID int64 7 | VaultName string 8 | Action string 9 | FromAddress string 10 | ToAddress string 11 | Target string 12 | Sender string 13 | Amount string 14 | Token string 15 | Threshold string 16 | CreatedAt string 17 | UpdatedAt string 18 | } 19 | -------------------------------------------------------------------------------- /pkg/model/monthly_delivery_metric.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/shopspring/decimal" 7 | ) 8 | 9 | type MonthlyDeliveryMetric struct { 10 | Month *time.Time 11 | SumWeight decimal.Decimal 12 | SumEffort decimal.Decimal 13 | } 14 | 15 | type AvgMonthlyDeliveryMetric struct { 16 | Weight decimal.Decimal 17 | Effort decimal.Decimal 18 | } 19 | -------------------------------------------------------------------------------- /pkg/model/news.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import "time" 4 | 5 | const ( 6 | RedditPlatform = "reddit" 7 | LobstersPlatform = "lobsters" 8 | ) 9 | 10 | type News struct { 11 | Title string 12 | URL string 13 | Popularity int64 14 | CommentCount int64 15 | Flag int64 16 | Description string 17 | Tags []string 18 | CreatedAt time.Time 19 | } 20 | -------------------------------------------------------------------------------- /pkg/model/notion_event.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | type NotionEvent struct { 8 | ID string `json:"id"` 9 | Name string `json:"name"` 10 | Date DateTime `json:"date"` 11 | ActivityType string `json:"activity_type"` 12 | CreatedAt time.Time `json:"created_at"` 13 | } 14 | -------------------------------------------------------------------------------- /pkg/model/onleave_request.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | type OnLeaveRequest struct { 8 | BaseModel 9 | 10 | Type string 11 | StartDate *time.Time 12 | EndDate *time.Time 13 | Shift string 14 | Title string 15 | Description string 16 | CreatorID UUID 17 | ApproverID UUID 18 | AssigneeIDs JSONArrayString 19 | 20 | Creator *Employee 21 | Approver *Employee 22 | } 23 | -------------------------------------------------------------------------------- /pkg/model/operational_service.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import "time" 4 | 5 | type OperationalService struct { 6 | BaseModel 7 | 8 | Name string 9 | Amount int 10 | Note string 11 | RegisterDate time.Time 12 | StartAt time.Time 13 | EndAt time.Time 14 | IsActive bool 15 | CurrencyID UUID 16 | Currency *Currency `gorm:"foreignKey:CurrencyID;references:ID"` 17 | } 18 | -------------------------------------------------------------------------------- /pkg/model/organization.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | const ( 4 | OrganizationCodeDwarves = "dwarves-foundation" 5 | OrganizationNameDwarves = "Dwarves Foundation" 6 | ) 7 | 8 | type Organization struct { 9 | BaseModel 10 | 11 | Name string `json:"name"` 12 | Code string `json:"code"` 13 | Avatar string `json:"avatar"` 14 | } 15 | 16 | // ToOrganizationMap create map from organizations 17 | func ToOrganizationMap(organizations []*Organization) map[UUID]string { 18 | rs := map[UUID]string{} 19 | for _, s := range organizations { 20 | rs[s.ID] = s.Name 21 | } 22 | 23 | return rs 24 | } 25 | -------------------------------------------------------------------------------- /pkg/model/physical_checkin_transactions.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import "time" 4 | 5 | type PhysicalCheckinTransaction struct { 6 | ID UUID 7 | EmployeeID UUID 8 | Date time.Time 9 | IcyAmount float64 10 | MochiTxID int64 11 | } 12 | 13 | func (PhysicalCheckinTransaction) TableName() string { return "physical_checkin_transactions" } 14 | -------------------------------------------------------------------------------- /pkg/model/positions.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type Position struct { 4 | BaseModel 5 | 6 | Name string `json:"name"` 7 | Code string `json:"code"` 8 | } 9 | 10 | // ToPositionMap create map from position 11 | func ToPositionMap(positions []*Position) map[UUID]Position { 12 | rs := map[UUID]Position{} 13 | for _, s := range positions { 14 | rs[s.ID] = *s 15 | } 16 | 17 | return rs 18 | } 19 | 20 | type Positions []Position 21 | 22 | func (p Positions) IsSales() bool { 23 | for _, position := range p { 24 | if position.Code == "sales" { 25 | return true 26 | } 27 | } 28 | return false 29 | } 30 | -------------------------------------------------------------------------------- /pkg/model/project_commission_configs.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import "github.com/shopspring/decimal" 4 | 5 | type ProjectCommissionConfig struct { 6 | BaseModel 7 | 8 | ProjectID UUID 9 | Position HeadPosition 10 | CommissionRate decimal.Decimal 11 | } 12 | 13 | type ProjectCommissionConfigs []ProjectCommissionConfig 14 | 15 | func (m *ProjectCommissionConfigs) ToMap() map[string]decimal.Decimal { 16 | rs := make(map[string]decimal.Decimal) 17 | for _, itm := range *m { 18 | rs[itm.Position.String()] = itm.CommissionRate 19 | } 20 | return rs 21 | } 22 | -------------------------------------------------------------------------------- /pkg/model/project_info.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type ProjectInfo struct { 4 | BaseModel 5 | 6 | ProjectID *UUID `json:"project_id"` 7 | BasecampBucketID int64 `json:"basecamp_bucket_id"` 8 | BasecampScheduleID int64 `json:"basecamp_schedule_id"` 9 | BasecampCampfireID int64 `json:"basecamp_campfire_id"` 10 | BasecampTodolistID int64 `json:"basecamp_todolist_id"` 11 | BasecampMessageBoardID int64 `json:"basecamp_message_board_id"` 12 | BasecampSentryID int64 `json:"basecamp_sentry_id"` 13 | GitlabID int64 `json:"gitlab_id"` 14 | Repositories JSON `json:"repositories"` 15 | 16 | Project *Project `json:"project"` 17 | } 18 | -------------------------------------------------------------------------------- /pkg/model/project_issue.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type ProjectIssue struct { 4 | ID int `json:"id"` 5 | Name string `json:"name"` 6 | Link string `json:"link"` 7 | } 8 | -------------------------------------------------------------------------------- /pkg/model/project_member_positions.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type ProjectMemberPosition struct { 4 | BaseModel 5 | 6 | ProjectMemberID UUID 7 | PositionID UUID 8 | 9 | Position Position 10 | } 11 | -------------------------------------------------------------------------------- /pkg/model/project_notion.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type ProjectNotion struct { 4 | BaseModel 5 | 6 | ProjectID UUID 7 | AuditNotionID UUID 8 | 9 | Project *Project `gorm:"foreignKey:project_id"` 10 | } 11 | -------------------------------------------------------------------------------- /pkg/model/project_slot_positions.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type ProjectSlotPosition struct { 4 | BaseModel 5 | 6 | ProjectSlotID UUID 7 | PositionID UUID 8 | 9 | Position Position 10 | } 11 | -------------------------------------------------------------------------------- /pkg/model/research_topic.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import "time" 4 | 5 | // DiscordResearchTopic represents discord research topic 6 | type DiscordResearchTopic struct { 7 | Name string 8 | URL string 9 | MsgCount int64 10 | SortedActiveUsers []DiscordTopicActiveUser 11 | LastActiveTime time.Time 12 | } 13 | 14 | // DiscordTopicActiveUser represents active users who send most messages in topic 15 | type DiscordTopicActiveUser struct { 16 | UserID string 17 | MsgCount int64 18 | } 19 | -------------------------------------------------------------------------------- /pkg/model/roles.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | const ( 4 | RoleFullTimeCode = "full-time" 5 | RoleProjectLeadCode = "project-lead" 6 | ) 7 | 8 | type Role struct { 9 | BaseModel 10 | 11 | Name string `json:"name"` 12 | Code string `json:"code"` 13 | Level int64 `json:"level"` 14 | Color string `json:"color"` 15 | IsShow bool `json:"isShow"` 16 | 17 | Employees []Employee `gorm:"many2many:employee_roles;"` 18 | } 19 | -------------------------------------------------------------------------------- /pkg/model/senitorities.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type Seniority struct { 4 | BaseModel 5 | 6 | Name string `json:"name"` 7 | Code string `json:"code"` 8 | Level int `json:"level"` 9 | } 10 | -------------------------------------------------------------------------------- /pkg/model/stacks.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type Stack struct { 4 | BaseModel 5 | 6 | Name string `json:"name"` 7 | Code string `json:"code"` 8 | Avatar string `json:"avatar"` 9 | } 10 | 11 | // ToStackMap create map from stacks 12 | func ToStackMap(stacks []*Stack) map[UUID]string { 13 | rs := map[UUID]string{} 14 | for _, s := range stacks { 15 | rs[s.ID] = s.Name 16 | } 17 | 18 | return rs 19 | } 20 | -------------------------------------------------------------------------------- /pkg/model/transferwise.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | // TWQuote defines a structure for quote request in transferwise 4 | type TWQuote struct { 5 | SourceAmount float64 `json:"sourceAmount"` 6 | Fee float64 `json:"fee"` 7 | Rate float64 `json:"rate"` 8 | } 9 | 10 | type TWRate struct { 11 | Rate float64 `json:"rate"` 12 | Source string `json:"source"` 13 | Target string `json:"target"` 14 | } 15 | -------------------------------------------------------------------------------- /pkg/model/user_bank_accounts.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type UserBankAccount struct { 4 | BaseModel 5 | 6 | EmployerID UUID 7 | DiscordAccountID UUID 8 | BankID UUID 9 | AccountNumber string 10 | Branch string 11 | } 12 | -------------------------------------------------------------------------------- /pkg/model/weekly_delivery_metric.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/shopspring/decimal" 7 | ) 8 | 9 | type WeeklyDeliveryMetric struct { 10 | Date *time.Time 11 | SumWeight decimal.Decimal 12 | SumEffort decimal.Decimal 13 | } 14 | 15 | type AvgWeeklyDeliveryMetric struct { 16 | Weight decimal.Decimal 17 | Effort decimal.Decimal 18 | } 19 | 20 | type AvgMonthWeeklyDeliveryMetric struct { 21 | Date *time.Time 22 | Weight decimal.Decimal 23 | Effort decimal.Decimal 24 | } 25 | -------------------------------------------------------------------------------- /pkg/model/wise.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type WiseConversionRate struct { 4 | Rate float64 `json:"rate"` 5 | Source string `json:"source"` 6 | Target string `json:"target"` 7 | } 8 | -------------------------------------------------------------------------------- /pkg/model/work_unit_stacks.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type WorkUnitStack struct { 4 | BaseModel 5 | 6 | StackID UUID 7 | WorkUnitID UUID 8 | 9 | Stack Stack 10 | } 11 | -------------------------------------------------------------------------------- /pkg/model/worker_message.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type Action uint8 4 | 5 | type WorkerMessage struct { 6 | Type string 7 | Payload interface{} 8 | } 9 | -------------------------------------------------------------------------------- /pkg/mw/errors.go: -------------------------------------------------------------------------------- 1 | package mw 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | ) 7 | 8 | var ( 9 | ErrUnauthorized = errors.New("unauthorized") 10 | ErrInvalidUserID = errors.New("invalid user id") 11 | ErrAuthenticationTypeHeaderInvalid = errors.New("authentication type header is invalid") 12 | ErrUnexpectedAuthorizationHeader = errors.New("unexpected authorization headers") 13 | ErrInvalidAPIKey = errors.New("invalid API key") 14 | ) 15 | 16 | // errUnauthorized returns unauthorized custom error 17 | func errUnauthorized(description string) error { 18 | return fmt.Errorf("unauthorized permission required: %v", description) 19 | } 20 | -------------------------------------------------------------------------------- /pkg/service/basecamp/attachment/service.go: -------------------------------------------------------------------------------- 1 | package attachment 2 | 3 | type Service interface { 4 | Create(contentType string, fileName string, file []byte) (id string, err error) 5 | } 6 | -------------------------------------------------------------------------------- /pkg/service/basecamp/campfire/service.go: -------------------------------------------------------------------------------- 1 | package campfire 2 | 3 | type Service interface { 4 | CreateLine(projectID int, campfireID int, line string) (err error) 5 | BotCreateLine(projectID int, campfireID int, line string) (err error) 6 | BotReply(callbackURL string, message string) (err error) 7 | } 8 | -------------------------------------------------------------------------------- /pkg/service/basecamp/client/service.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import "net/http" 4 | 5 | type Service interface { 6 | Get(url string) (resp *http.Response, err error) 7 | Do(req *http.Request) (resp *http.Response, err error) 8 | GetAccessToken(code string, redirectURI string) (accessToken string, err error) 9 | } 10 | -------------------------------------------------------------------------------- /pkg/service/basecamp/comment/service.go: -------------------------------------------------------------------------------- 1 | package comment 2 | 3 | import "github.com/dwarvesf/fortress-api/pkg/service/basecamp/model" 4 | 5 | type Service interface { 6 | Create(projectID int, recordingID int, comment *model.Comment) (err error) 7 | Gets(projectID int, recordingID int) (res []model.Comment, err error) 8 | } 9 | -------------------------------------------------------------------------------- /pkg/service/basecamp/messageboard/service.go: -------------------------------------------------------------------------------- 1 | package messageboard 2 | 3 | import "github.com/dwarvesf/fortress-api/pkg/service/basecamp/model" 4 | 5 | // Service -- message board service 6 | type Service interface { 7 | Create(message *model.Message, projectID, messageBoardID int) (err error) 8 | GetList(projectID int, messageBoardID int) (messages []model.Message, err error) 9 | Get(projectID int, messageID int) (message model.Message, err error) 10 | } 11 | -------------------------------------------------------------------------------- /pkg/service/basecamp/people/service.go: -------------------------------------------------------------------------------- 1 | package people 2 | 3 | import ( 4 | "errors" 5 | 6 | "github.com/dwarvesf/fortress-api/pkg/service/basecamp/model" 7 | ) 8 | 9 | var ( 10 | ErrNotInProject = errors.New("this account does not belong to this project") 11 | ) 12 | 13 | type Service interface { 14 | GetByID(id int) (res *model.Person, err error) 15 | GetInfo() (res *model.UserInfo, err error) 16 | Create(name string, email string, orgnization string) (id int64, sgID string, err error) 17 | Remove(userID int64) (err error) 18 | UpdateInProject(projectID int64, peopleEntry model.PeopleEntry) (id int64, sgID string, err error) 19 | GetAllOnProject(projectID int) (result []model.Person, err error) 20 | } 21 | -------------------------------------------------------------------------------- /pkg/service/basecamp/project/service.go: -------------------------------------------------------------------------------- 1 | package project 2 | 3 | import "github.com/dwarvesf/fortress-api/pkg/service/basecamp/model" 4 | 5 | type Service interface { 6 | GetAll() (result []model.Project, err error) 7 | Get(id int) (result model.Project, err error) 8 | } 9 | -------------------------------------------------------------------------------- /pkg/service/basecamp/recording/service.go: -------------------------------------------------------------------------------- 1 | package recording 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/dwarvesf/fortress-api/pkg/service/basecamp/model" 7 | ) 8 | 9 | type Service interface { 10 | GetFrom(from time.Time, recordingType string) ([]model.Recording, error) 11 | GetEvents(from time.Time, projectID, recordingID int) ([]model.Event, error) 12 | Trash(projectID string, recordingID string) (err error) 13 | Archive(projectID, recordingID int) error 14 | TryToGetInvoiceImageURL(url string) (res string, err error) 15 | } 16 | -------------------------------------------------------------------------------- /pkg/service/basecamp/schedule/service.go: -------------------------------------------------------------------------------- 1 | package schedule 2 | 3 | import "github.com/dwarvesf/fortress-api/pkg/service/basecamp/model" 4 | 5 | type Service interface { 6 | CreateScheduleEntry(projectID int64, scheduleID int64, scheduleEntry model.ScheduleEntry) (res *model.ScheduleEntry, err error) 7 | GetScheduleEntries(projectID int64, scheduleID int64) (res []*model.ScheduleEntry, err error) 8 | UpdateSheduleEntry(projectID int64, se *model.ScheduleEntry) (err error) 9 | } 10 | -------------------------------------------------------------------------------- /pkg/service/basecamp/subscription/service.go: -------------------------------------------------------------------------------- 1 | package subscription 2 | 3 | import "github.com/dwarvesf/fortress-api/pkg/service/basecamp/model" 4 | 5 | type Service interface { 6 | Subscribe(url string, list *model.SubscriptionList) (err error) 7 | } 8 | -------------------------------------------------------------------------------- /pkg/service/basecamp/webhook/service.go: -------------------------------------------------------------------------------- 1 | package webhook 2 | 3 | import "github.com/dwarvesf/fortress-api/pkg/service/basecamp/model" 4 | 5 | type Service interface { 6 | FindWebHook(projectID int, hookID int) (result *model.Hook, err error) 7 | UpdateWebHook(projectID int, hookID int, hookBody model.Hook) (err error) 8 | } 9 | -------------------------------------------------------------------------------- /pkg/service/evm/model.go: -------------------------------------------------------------------------------- 1 | package evm 2 | 3 | type RpcClient struct { 4 | Url string 5 | } 6 | 7 | var ( 8 | DefaultBASEClient = RpcClient{Url: "https://mainnet.base.org"} 9 | ) 10 | -------------------------------------------------------------------------------- /pkg/service/git/inteface.go: -------------------------------------------------------------------------------- 1 | package git 2 | 3 | type IService interface { 4 | Dest() string 5 | CreateBranch(branchName string) (err error) 6 | Commit(message string) (err error) 7 | Push() (err error) 8 | CreatePullRequest(owner, repo, head, base, title, body string) (*int, error) 9 | RequestReview(owner, repo string, pullRequestNumber int, reviewers []string) error 10 | } 11 | -------------------------------------------------------------------------------- /pkg/service/github/errors.go: -------------------------------------------------------------------------------- 1 | package github 2 | 3 | import "errors" 4 | 5 | var ( 6 | ErrFailedToGetGithubAccount = errors.New("failed to get github account") 7 | ErrFoundOneMoreGithubAccount = errors.New("failed to get github account due to more than 1 github account found") 8 | ) 9 | -------------------------------------------------------------------------------- /pkg/service/github/service.go: -------------------------------------------------------------------------------- 1 | package github 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/google/go-github/v52/github" 7 | 8 | "github.com/dwarvesf/fortress-api/pkg/model" 9 | ) 10 | 11 | type IService interface { 12 | RemoveFromOrganizationByEmail(ctx context.Context, email string) error 13 | RemoveFromOrganizationByUsername(ctx context.Context, username string) error 14 | SendInvitationByEmail(ctx context.Context, e *model.Employee) error 15 | RetrieveUsernameByID(ctx context.Context, id int64) (string, error) 16 | FetchOpenPullRequest(ctx context.Context, repo string) ([]*github.PullRequest, error) 17 | } 18 | -------------------------------------------------------------------------------- /pkg/service/google/interface.go: -------------------------------------------------------------------------------- 1 | package google 2 | 3 | type IService interface { 4 | GetLoginURL() string 5 | GetAccessToken(code string, redirectURL string) (accessToken string, err error) 6 | GetGoogleEmailLegacy(accessToken string) (email string, err error) 7 | GetGoogleEmail(accessToken string) (email string, err error) 8 | } 9 | -------------------------------------------------------------------------------- /pkg/service/googleadmin/interface.go: -------------------------------------------------------------------------------- 1 | package googleadmin 2 | 3 | // IService interface contain related google calendar method 4 | type IService interface { 5 | GetGroupMemberEmails(groupEmail string) ([]string, error) 6 | DeleteAccount(mail string) error 7 | } 8 | -------------------------------------------------------------------------------- /pkg/service/googledrive/interface.go: -------------------------------------------------------------------------------- 1 | package googledrive 2 | 3 | import ( 4 | "errors" 5 | 6 | "github.com/dwarvesf/fortress-api/pkg/model" 7 | ) 8 | 9 | var ( 10 | ErrInvoicePDFNotFound = errors.New("invoice pdf not found") 11 | ) 12 | 13 | type IService interface { 14 | UploadInvoicePDF(invoice *model.Invoice, dirName string) error 15 | MoveInvoicePDF(invoice *model.Invoice, fromDirName, toDirName string) error 16 | DownloadInvoicePDF(invoice *model.Invoice, dirName string) ([]byte, error) 17 | } 18 | -------------------------------------------------------------------------------- /pkg/service/googlesheet/interface.go: -------------------------------------------------------------------------------- 1 | package googlesheet 2 | 3 | var () 4 | 5 | type IService interface { 6 | FetchSheetContent(fromIdx int) ([]DeliveryMetricRawData, error) 7 | } 8 | -------------------------------------------------------------------------------- /pkg/service/googlesheet/types.go: -------------------------------------------------------------------------------- 1 | package googlesheet 2 | 3 | type SheetData struct { 4 | Range string `json:"range"` 5 | MajorDimension string `json:"majorDimension"` 6 | Values [][]string `json:"values"` 7 | } 8 | 9 | type DeliveryMetricRawData struct { 10 | Person string `json:"person"` 11 | Weight string `json:"weight"` 12 | Effort string `json:"effort"` 13 | Effectiveness string `json:"effectiveness"` 14 | Date string `json:"date"` 15 | Project string `json:"project"` 16 | Email string `json:"email"` 17 | } 18 | -------------------------------------------------------------------------------- /pkg/service/googlestorage/gcs.go: -------------------------------------------------------------------------------- 1 | package googlestorage 2 | 3 | import ( 4 | "cloud.google.com/go/storage" 5 | ) 6 | 7 | type CloudStorage struct { 8 | client *storage.Client 9 | projectID string 10 | bucketName string 11 | } 12 | -------------------------------------------------------------------------------- /pkg/service/googlestorage/interface.go: -------------------------------------------------------------------------------- 1 | package googlestorage 2 | 3 | import ( 4 | "io" 5 | ) 6 | 7 | type IService interface { 8 | UploadContentGCS(file io.Reader, fileName string) error 9 | } 10 | -------------------------------------------------------------------------------- /pkg/service/improvmx/service.go: -------------------------------------------------------------------------------- 1 | package improvmx 2 | 3 | type IService interface { 4 | CreateAccount(email, fwdEmail string) error 5 | DeleteAccount(email string) error 6 | } 7 | -------------------------------------------------------------------------------- /pkg/service/landingzone/gcs.go: -------------------------------------------------------------------------------- 1 | package landingzone 2 | 3 | import ( 4 | "cloud.google.com/go/storage" 5 | ) 6 | 7 | type CloudStorage struct { 8 | client *storage.Client 9 | bucketName string 10 | } 11 | -------------------------------------------------------------------------------- /pkg/service/landingzone/interface.go: -------------------------------------------------------------------------------- 1 | package landingzone 2 | 3 | import ( 4 | "context" 5 | "io" 6 | ) 7 | 8 | type IService interface { 9 | UploadContentGCS(file io.Reader, fileName string) error 10 | CreateOrUpdateEvents(ctx context.Context, filePath string, newEvent map[string]interface{}) error 11 | } 12 | -------------------------------------------------------------------------------- /pkg/service/lobsters/interface.go: -------------------------------------------------------------------------------- 1 | package lobsters 2 | 3 | type IService interface { 4 | FetchNews(tag string) ([]LobsterPost, error) 5 | } 6 | -------------------------------------------------------------------------------- /pkg/service/lobsters/new.go: -------------------------------------------------------------------------------- 1 | package lobsters 2 | 3 | type service struct { 4 | } 5 | 6 | func New() IService { 7 | return &service{} 8 | } 9 | -------------------------------------------------------------------------------- /pkg/service/mochi/model.go: -------------------------------------------------------------------------------- 1 | package mochi 2 | 3 | // Vault is the model for mochi vault that is fetched from mochi-api 4 | type Vault struct { 5 | ID int64 `json:"id"` 6 | GuildID string `json:"guild_id"` 7 | } 8 | -------------------------------------------------------------------------------- /pkg/service/mochi/response.go: -------------------------------------------------------------------------------- 1 | package mochi 2 | 3 | // GetListVaultsResponse is the response model for mochi-api GetListVaults 4 | type GetListVaultsResponse struct { 5 | Data []Vault `json:"data"` 6 | } 7 | -------------------------------------------------------------------------------- /pkg/service/ogifmemosummarizer/interface.go: -------------------------------------------------------------------------------- 1 | package ogifmemosummarizer 2 | 3 | type IService interface { 4 | SummarizeOGIFMemo(youtubeURL string) (content string, err error) 5 | } 6 | -------------------------------------------------------------------------------- /pkg/service/reddit/fetch_go_news.go: -------------------------------------------------------------------------------- 1 | package reddit 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/vartanbeno/go-reddit/v2/reddit" 7 | ) 8 | 9 | const ( 10 | redditGolangChannel = "golang" 11 | ) 12 | 13 | // FetchGolangNews fetches the latest Golang news posts from the rising posts. 14 | func (s *service) FetchGolangNews(ctx context.Context) ([]*reddit.Post, error) { 15 | risingPosts, _, err := s.client.Subreddit.RisingPosts(ctx, redditGolangChannel, &reddit.ListOptions{ 16 | Limit: 50, 17 | }) 18 | if err != nil { 19 | return nil, err 20 | } 21 | 22 | return risingPosts, nil 23 | } 24 | -------------------------------------------------------------------------------- /pkg/service/reddit/interface.go: -------------------------------------------------------------------------------- 1 | package reddit 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/vartanbeno/go-reddit/v2/reddit" 7 | ) 8 | 9 | type IService interface { 10 | // FetchGolangNews fetches the latest Golang news posts and filters the rising posts from the new posts. 11 | FetchGolangNews(ctx context.Context) ([]*reddit.Post, error) 12 | } 13 | -------------------------------------------------------------------------------- /pkg/service/tono/request.go: -------------------------------------------------------------------------------- 1 | package tono 2 | 3 | type GetGuildProfileResponse struct { 4 | Data GuildProfile `json:"data"` 5 | } 6 | 7 | type GuildProfile struct { 8 | ID string `json:"id"` 9 | CurrentLevel *ConfigXpLevel `json:"current_level"` 10 | NextLevel *ConfigXpLevel `json:"next_level"` 11 | GuildXP int `json:"guild_xp"` 12 | NrOfActions int `json:"nr_of_actions"` 13 | Progress float64 `json:"progress"` 14 | GuildRank int `json:"guild_rank"` 15 | } 16 | 17 | type ConfigXpLevel struct { 18 | Level int `json:"level" gorm:"primaryKey"` 19 | MinXP int `json:"min_xp"` 20 | } 21 | -------------------------------------------------------------------------------- /pkg/service/vault/interface.go: -------------------------------------------------------------------------------- 1 | package vault 2 | 3 | type IService interface { 4 | GetString(key string) string 5 | GetBool(key string) bool 6 | } 7 | -------------------------------------------------------------------------------- /pkg/service/wise/interface.go: -------------------------------------------------------------------------------- 1 | package wise 2 | 3 | import "github.com/dwarvesf/fortress-api/pkg/model" 4 | 5 | type IService interface { 6 | Convert(amount float64, source, target string) (convertedAmount float64, rate float64, error error) 7 | GetPayrollQuotes(sourceCurrency, targetCurrency string, targetAmount float64) (*model.TWQuote, error) 8 | GetRate(source, target string) (rate float64, err error) 9 | } 10 | -------------------------------------------------------------------------------- /pkg/service/youtube/interface.go: -------------------------------------------------------------------------------- 1 | package youtube 2 | 3 | import ( 4 | "github.com/dwarvesf/fortress-api/pkg/model" 5 | "google.golang.org/api/youtube/v3" 6 | ) 7 | 8 | // IService interface contain related google calendar method 9 | type IService interface { 10 | GetLatestBroadcast() (*youtube.LiveBroadcast, error) 11 | CreateBroadcast(*model.Event) (err error) 12 | } 13 | -------------------------------------------------------------------------------- /pkg/store/accounting/interface.go: -------------------------------------------------------------------------------- 1 | package accounting 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | 6 | "github.com/dwarvesf/fortress-api/pkg/model" 7 | ) 8 | 9 | // IStore implement calendar method 10 | type IStore interface { 11 | CreateTransaction(db *gorm.DB, transaction *model.AccountingTransaction) error 12 | GetAccountingTransactions(db *gorm.DB) ([]model.AccountingTransaction, error) 13 | GetAccountingCategories(db *gorm.DB) ([]model.AccountingCategory, error) 14 | DeleteTransaction(db *gorm.DB, t *model.AccountingTransaction) error 15 | CreateMultipleTransaction(db *gorm.DB, transactions []*model.AccountingTransaction) error 16 | } 17 | -------------------------------------------------------------------------------- /pkg/store/actionitem/interface.go: -------------------------------------------------------------------------------- 1 | package actionitem 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | 6 | "github.com/dwarvesf/fortress-api/pkg/model" 7 | ) 8 | 9 | type IStore interface { 10 | One(db *gorm.DB, id string) (actionItem *model.ActionItem, err error) 11 | All(db *gorm.DB) (actionItems []*model.ActionItem, err error) 12 | Delete(db *gorm.DB, id string) (err error) 13 | Create(db *gorm.DB, e *model.ActionItem) (actionItem *model.ActionItem, err error) 14 | Update(db *gorm.DB, actionItem *model.ActionItem) (ac *model.ActionItem, err error) 15 | UpdateSelectedFieldsByID(db *gorm.DB, id string, actionItem model.ActionItem, updatedFields ...string) (ac *model.ActionItem, err error) 16 | } 17 | -------------------------------------------------------------------------------- /pkg/store/apikey/api_key.go: -------------------------------------------------------------------------------- 1 | package apikey 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | 6 | "github.com/dwarvesf/fortress-api/pkg/model" 7 | ) 8 | 9 | type store struct{} 10 | 11 | func New() IStore { 12 | return &store{} 13 | } 14 | 15 | func (s *store) GetByClientID(db *gorm.DB, id string) (*model.APIKey, error) { 16 | var apikey *model.APIKey 17 | return apikey, db.Where("client_id = ?", id). 18 | First(&apikey).Error 19 | } 20 | 21 | func (s *store) Create(db *gorm.DB, e *model.APIKey) (apiKey *model.APIKey, err error) { 22 | return e, db.Create(e).Error 23 | } 24 | -------------------------------------------------------------------------------- /pkg/store/apikey/interface.go: -------------------------------------------------------------------------------- 1 | package apikey 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | 6 | "github.com/dwarvesf/fortress-api/pkg/model" 7 | ) 8 | 9 | type IStore interface { 10 | GetByClientID(db *gorm.DB, id string) (*model.APIKey, error) 11 | Create(db *gorm.DB, e *model.APIKey) (apiKey *model.APIKey, err error) 12 | } 13 | -------------------------------------------------------------------------------- /pkg/store/apikeyrole/api_key_role.go: -------------------------------------------------------------------------------- 1 | package apikeyrole 2 | 3 | import ( 4 | "github.com/dwarvesf/fortress-api/pkg/model" 5 | "gorm.io/gorm" 6 | ) 7 | 8 | type store struct{} 9 | 10 | func New() IStore { 11 | return &store{} 12 | } 13 | 14 | func (s *store) Create(db *gorm.DB, e *model.APIKeyRole) (*model.APIKeyRole, error) { 15 | return e, db.Create(e).Error 16 | } 17 | -------------------------------------------------------------------------------- /pkg/store/apikeyrole/interface.go: -------------------------------------------------------------------------------- 1 | package apikeyrole 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | 6 | "github.com/dwarvesf/fortress-api/pkg/model" 7 | ) 8 | 9 | type IStore interface { 10 | Create(db *gorm.DB, e *model.APIKeyRole) (*model.APIKeyRole, error) 11 | } 12 | -------------------------------------------------------------------------------- /pkg/store/audit/interface.go: -------------------------------------------------------------------------------- 1 | package audit 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | 6 | "github.com/dwarvesf/fortress-api/pkg/model" 7 | ) 8 | 9 | type IStore interface { 10 | One(db *gorm.DB, id string) (audit *model.Audit, err error) 11 | All(db *gorm.DB) (audits []*model.Audit, err error) 12 | Delete(db *gorm.DB, id string) (err error) 13 | Create(db *gorm.DB, e *model.Audit) (audit *model.Audit, err error) 14 | Update(db *gorm.DB, audit *model.Audit) (a *model.Audit, err error) 15 | UpdateSelectedFieldsByID(db *gorm.DB, id string, audit model.Audit, updatedFields ...string) (a *model.Audit, err error) 16 | ResetActionItem(db *gorm.DB) (err error) 17 | } 18 | -------------------------------------------------------------------------------- /pkg/store/bank/interface.go: -------------------------------------------------------------------------------- 1 | package bank 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | 6 | "github.com/dwarvesf/fortress-api/pkg/model" 7 | ) 8 | 9 | type IStore interface { 10 | One(db *gorm.DB, id string) (bank *model.Bank, err error) 11 | OneByBin(db *gorm.DB, bin string) (bank *model.Bank, err error) 12 | OneBySwiftCode(db *gorm.DB, code string) (bank *model.Bank, err error) 13 | All(db *gorm.DB, in GetBanksInput) ([]*model.Bank, error) 14 | IsExist(db *gorm.DB, id string) (exists bool, err error) 15 | } 16 | -------------------------------------------------------------------------------- /pkg/store/bankaccount/interface.go: -------------------------------------------------------------------------------- 1 | package bankaccount 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | 6 | "github.com/dwarvesf/fortress-api/pkg/model" 7 | ) 8 | 9 | type IStore interface { 10 | One(db *gorm.DB, id string) (bankAccount *model.BankAccount, err error) 11 | All(db *gorm.DB) (bankAccounts []*model.BankAccount, err error) 12 | IsExist(db *gorm.DB, id string) (exists bool, err error) 13 | } 14 | -------------------------------------------------------------------------------- /pkg/store/basesalary/interface.go: -------------------------------------------------------------------------------- 1 | package basesalary 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | 6 | "github.com/dwarvesf/fortress-api/pkg/model" 7 | ) 8 | 9 | type IStore interface { 10 | One(db *gorm.DB, id string) (baseSalary *model.BaseSalary, err error) 11 | OneByEmployeeID(db *gorm.DB, employeeID string) (baseSalary *model.BaseSalary, err error) 12 | Save(db *gorm.DB, baseSalary *model.BaseSalary) (err error) 13 | } 14 | -------------------------------------------------------------------------------- /pkg/store/brainerylog/interface.go: -------------------------------------------------------------------------------- 1 | package brainerylog 2 | 3 | import ( 4 | "time" 5 | 6 | "gorm.io/gorm" 7 | 8 | "github.com/dwarvesf/fortress-api/pkg/model" 9 | ) 10 | 11 | type IStore interface { 12 | Create(db *gorm.DB, b []model.BraineryLog) ([]model.BraineryLog, error) 13 | GetLimitByTimeRange(db *gorm.DB, start, end *time.Time, limit int) ([]*model.BraineryLog, error) 14 | GetNewContributorDiscordIDs(db *gorm.DB, start, end *time.Time) ([]string, error) 15 | } 16 | -------------------------------------------------------------------------------- /pkg/store/cachedpayroll/cached_payroll.go: -------------------------------------------------------------------------------- 1 | package cachedpayroll 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | 6 | "github.com/dwarvesf/fortress-api/pkg/model" 7 | ) 8 | 9 | type store struct{} 10 | 11 | // New create new pg service 12 | func New() IStore { 13 | return &store{} 14 | } 15 | 16 | func (s *store) Set(db *gorm.DB, cachedPayroll *model.CachedPayroll) error { 17 | return db.Save(cachedPayroll).Error 18 | } 19 | 20 | func (s *store) Get(db *gorm.DB, month, year, batch int) (*model.CachedPayroll, error) { 21 | p := model.CachedPayroll{} 22 | return &p, db.Where("month = ? AND year = ? AND batch = ?", month, year, batch).First(&p).Error 23 | } 24 | -------------------------------------------------------------------------------- /pkg/store/cachedpayroll/interface.go: -------------------------------------------------------------------------------- 1 | package cachedpayroll 2 | 3 | import ( 4 | "github.com/dwarvesf/fortress-api/pkg/model" 5 | "gorm.io/gorm" 6 | ) 7 | 8 | type IStore interface { 9 | Set(db *gorm.DB, cachedPayroll *model.CachedPayroll) error 10 | Get(db *gorm.DB, month, year, batch int) (*model.CachedPayroll, error) 11 | } 12 | -------------------------------------------------------------------------------- /pkg/store/chapter/interface.go: -------------------------------------------------------------------------------- 1 | package chapter 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | 6 | "github.com/dwarvesf/fortress-api/pkg/model" 7 | ) 8 | 9 | type IStore interface { 10 | All(db *gorm.DB) (chapters []*model.Chapter, err error) 11 | IsExist(db *gorm.DB, id string) (isExist bool, err error) 12 | UpdateChapterLead(db *gorm.DB, id string, lead *model.UUID) (err error) 13 | GetAllByLeadID(db *gorm.DB, leadID string) (chapters []*model.Chapter, err error) 14 | } 15 | -------------------------------------------------------------------------------- /pkg/store/client/interface.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | 6 | "github.com/dwarvesf/fortress-api/pkg/model" 7 | ) 8 | 9 | type IStore interface { 10 | One(db *gorm.DB, id string) (client *model.Client, err error) 11 | IsExist(db *gorm.DB, id string) (exists bool, err error) 12 | All(db *gorm.DB, public bool, preload bool) ([]*model.Client, error) 13 | Delete(db *gorm.DB, id string) (err error) 14 | Create(db *gorm.DB, e *model.Client) (client *model.Client, err error) 15 | Update(db *gorm.DB, client *model.Client) (a *model.Client, err error) 16 | UpdateSelectedFieldsByID(db *gorm.DB, id string, client model.Client, updatedFields ...string) (a *model.Client, err error) 17 | } 18 | -------------------------------------------------------------------------------- /pkg/store/companyinfo/interface.go: -------------------------------------------------------------------------------- 1 | package companyinfo 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | 6 | "github.com/dwarvesf/fortress-api/pkg/model" 7 | ) 8 | 9 | type IStore interface { 10 | One(db *gorm.DB, id string) (companyInfo *model.CompanyInfo, err error) 11 | IsExist(db *gorm.DB, id string) (exists bool, err error) 12 | All(db *gorm.DB) (companyInfos []*model.CompanyInfo, err error) 13 | } 14 | -------------------------------------------------------------------------------- /pkg/store/config/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | 6 | "github.com/dwarvesf/fortress-api/pkg/model" 7 | ) 8 | 9 | type store struct{} 10 | 11 | func New() IStore { 12 | return &store{} 13 | } 14 | 15 | func (s *store) One(db *gorm.DB, id string) (*model.Config, error) { 16 | var config *model.Config 17 | return config, db.Where("id = ?", id). 18 | First(&config).Error 19 | } 20 | 21 | func (s *store) OneByKey(db *gorm.DB, key string) (*model.Config, error) { 22 | var config *model.Config 23 | return config, db.Where("key = ?", key). 24 | First(&config).Error 25 | } 26 | 27 | func (s *store) Save(db *gorm.DB, config *model.Config) (err error) { 28 | return db.Save(&config).Error 29 | } 30 | -------------------------------------------------------------------------------- /pkg/store/config/interface.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | 6 | "github.com/dwarvesf/fortress-api/pkg/model" 7 | ) 8 | 9 | type IStore interface { 10 | One(db *gorm.DB, id string) (config *model.Config, err error) 11 | OneByKey(db *gorm.DB, key string) (config *model.Config, err error) 12 | Save(db *gorm.DB, salaryAdvance *model.Config) (err error) 13 | } 14 | -------------------------------------------------------------------------------- /pkg/store/content/content.go: -------------------------------------------------------------------------------- 1 | package content 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | 6 | "github.com/dwarvesf/fortress-api/pkg/model" 7 | ) 8 | 9 | type store struct { 10 | } 11 | 12 | func New() IStore { 13 | return &store{} 14 | } 15 | 16 | // Create a content record 17 | func (s *store) Create(tx *gorm.DB, content model.Content) (*model.Content, error) { 18 | return &content, tx.Create(&content).Error 19 | } 20 | 21 | // OneByPath get content by name 22 | func (s *store) OneByPath(tx *gorm.DB, path string) (*model.Content, error) { 23 | content := model.Content{} 24 | return &content, tx. 25 | Where("LOWER(path) = LOWER(?)", path).First(&content).Error 26 | } 27 | -------------------------------------------------------------------------------- /pkg/store/content/interface.go: -------------------------------------------------------------------------------- 1 | package content 2 | 3 | import ( 4 | "github.com/dwarvesf/fortress-api/pkg/model" 5 | "gorm.io/gorm" 6 | ) 7 | 8 | type IStore interface { 9 | Create(tx *gorm.DB, content model.Content) (*model.Content, error) 10 | OneByPath(tx *gorm.DB, path string) (*model.Content, error) 11 | } 12 | -------------------------------------------------------------------------------- /pkg/store/conversionrate/interface.go: -------------------------------------------------------------------------------- 1 | package conversionrate 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | 6 | "github.com/dwarvesf/fortress-api/pkg/model" 7 | ) 8 | 9 | type IStore interface { 10 | GetByCurrencyID(db *gorm.DB, id string) (*model.ConversionRate, error) 11 | GetList(db *gorm.DB) ([]model.ConversionRate, error) 12 | Update(db *gorm.DB, cr *model.ConversionRate) error 13 | } 14 | -------------------------------------------------------------------------------- /pkg/store/country/interface.go: -------------------------------------------------------------------------------- 1 | package country 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | 6 | "github.com/dwarvesf/fortress-api/pkg/model" 7 | ) 8 | 9 | type IStore interface { 10 | All(db *gorm.DB) (countries []*model.Country, err error) 11 | One(db *gorm.DB, id string) (countries *model.Country, err error) 12 | OneByName(db *gorm.DB, name string) (countries *model.Country, err error) 13 | IsExist(db *gorm.DB, id string) (bool, error) 14 | } 15 | -------------------------------------------------------------------------------- /pkg/store/currency/currency.go: -------------------------------------------------------------------------------- 1 | package currency 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | 6 | "github.com/dwarvesf/fortress-api/pkg/model" 7 | ) 8 | 9 | type currencyService struct{} 10 | 11 | // New create new pg service 12 | func New() IStore { 13 | return ¤cyService{} 14 | } 15 | 16 | func (c currencyService) GetByName(db *gorm.DB, name string) (*model.Currency, error) { 17 | currency := &model.Currency{} 18 | return currency, db.Where("name = ?", name).First(currency).Error 19 | } 20 | 21 | func (c currencyService) GetList(db *gorm.DB) ([]model.Currency, error) { 22 | var currencies []model.Currency 23 | return currencies, db.Find(¤cies).Error 24 | } 25 | -------------------------------------------------------------------------------- /pkg/store/currency/interface.go: -------------------------------------------------------------------------------- 1 | package currency 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | 6 | "github.com/dwarvesf/fortress-api/pkg/model" 7 | ) 8 | 9 | type IStore interface { 10 | GetByName(db *gorm.DB, name string) (*model.Currency, error) 11 | GetList(db *gorm.DB) ([]model.Currency, error) 12 | } 13 | -------------------------------------------------------------------------------- /pkg/store/deliverymetricmonthly/interface.go: -------------------------------------------------------------------------------- 1 | package deliverymetricmonthly 2 | 3 | import ( 4 | "time" 5 | 6 | "gorm.io/gorm" 7 | 8 | "github.com/dwarvesf/fortress-api/pkg/model" 9 | ) 10 | 11 | type IStore interface { 12 | GetLast(db *gorm.DB, num int) ([]model.MonthlyDeliveryMetric, error) 13 | AvgTo(db *gorm.DB, maxMonth *time.Time) (model.AvgMonthlyDeliveryMetric, error) 14 | } 15 | -------------------------------------------------------------------------------- /pkg/store/deliverymetricweekly/interface.go: -------------------------------------------------------------------------------- 1 | package deliverymetricweekly 2 | 3 | import ( 4 | "time" 5 | 6 | "gorm.io/gorm" 7 | 8 | "github.com/dwarvesf/fortress-api/pkg/model" 9 | ) 10 | 11 | type IStore interface { 12 | GetLast(db *gorm.DB, num int) ([]model.WeeklyDeliveryMetric, error) 13 | Avg(db *gorm.DB) (model.AvgWeeklyDeliveryMetric, error) 14 | AvgWithoutLatestWeek(db *gorm.DB) (model.AvgWeeklyDeliveryMetric, error) 15 | AvgByMonth(db *gorm.DB, month time.Time) ([]model.AvgMonthWeeklyDeliveryMetric, error) 16 | } 17 | -------------------------------------------------------------------------------- /pkg/store/discordtemplate/discord_template.go: -------------------------------------------------------------------------------- 1 | package discordtemplate 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | 6 | "github.com/dwarvesf/fortress-api/pkg/model" 7 | ) 8 | 9 | type store struct { 10 | } 11 | 12 | func New() IStore { 13 | return &store{} 14 | } 15 | 16 | func (s *store) GetTemplateByType(db *gorm.DB, templateType string) (*model.DiscordLogTemplate, error) { 17 | var template *model.DiscordLogTemplate 18 | return template, db.Where("type = ?", templateType).First(&template).Error 19 | } 20 | -------------------------------------------------------------------------------- /pkg/store/discordtemplate/interface.go: -------------------------------------------------------------------------------- 1 | package discordtemplate 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | 6 | "github.com/dwarvesf/fortress-api/pkg/model" 7 | ) 8 | 9 | type IStore interface { 10 | GetTemplateByType(db *gorm.DB, templateType string) (*model.DiscordLogTemplate, error) 11 | } 12 | -------------------------------------------------------------------------------- /pkg/store/employee/request.go: -------------------------------------------------------------------------------- 1 | package employee 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/dwarvesf/fortress-api/pkg/model" 7 | ) 8 | 9 | type EmployeeFilter struct { 10 | WorkingStatuses []string 11 | Preload bool 12 | Positions []string 13 | Stacks []string 14 | Projects []string 15 | Chapters []string 16 | Seniorities []string 17 | Organizations []string 18 | LineManagers []string 19 | Keyword string 20 | IsLeft *bool 21 | BatchDate *time.Time 22 | //field sort 23 | JoinedDateSort model.SortOrder 24 | } 25 | 26 | type DiscordRequestFilter struct { 27 | DiscordID []string 28 | Email string 29 | Keyword string 30 | } 31 | -------------------------------------------------------------------------------- /pkg/store/employeebonus/employee_bonus.go: -------------------------------------------------------------------------------- 1 | package employeebonus 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | 6 | "github.com/dwarvesf/fortress-api/pkg/model" 7 | ) 8 | 9 | type store struct{} 10 | 11 | // New initialize new store for bonus 12 | func New() IStore { 13 | return &store{} 14 | } 15 | 16 | func (s *store) GetByUserID(db *gorm.DB, id model.UUID) ([]model.EmployeeBonus, error) { 17 | var res []model.EmployeeBonus 18 | return res, db.Where("is_active = true AND employee_id = ?", id).Find(&res).Error 19 | } 20 | -------------------------------------------------------------------------------- /pkg/store/employeebonus/interface.go: -------------------------------------------------------------------------------- 1 | package employeebonus 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | 6 | "github.com/dwarvesf/fortress-api/pkg/model" 7 | ) 8 | 9 | // IStore is an interface that abstract database method for bonus 10 | type IStore interface { 11 | GetByUserID(db *gorm.DB, id model.UUID) ([]model.EmployeeBonus, error) 12 | } 13 | -------------------------------------------------------------------------------- /pkg/store/employeechapter/interface.go: -------------------------------------------------------------------------------- 1 | package employeechapter 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | 6 | "github.com/dwarvesf/fortress-api/pkg/model" 7 | ) 8 | 9 | type IStore interface { 10 | Create(db *gorm.DB, employeeChapter *model.EmployeeChapter) (*model.EmployeeChapter, error) 11 | DeleteByEmployeeID(db *gorm.DB, employeeID string) error 12 | } 13 | -------------------------------------------------------------------------------- /pkg/store/employeeeventquestion/request.go: -------------------------------------------------------------------------------- 1 | package employeeeventquestion 2 | 3 | type BasicEventQuestion struct { 4 | EventQuestionID string 5 | Answer string 6 | Note string 7 | } 8 | -------------------------------------------------------------------------------- /pkg/store/employeeeventtopic/request.go: -------------------------------------------------------------------------------- 1 | package employeeeventtopic 2 | 3 | type GetByEmployeeIDInput struct { 4 | Status string 5 | } 6 | 7 | type GetByEventIDInput struct { 8 | EventID string 9 | Keyword string 10 | Status string 11 | Projects []string 12 | Preload bool 13 | Paging bool 14 | } 15 | -------------------------------------------------------------------------------- /pkg/store/employeeinvitation/interface.go: -------------------------------------------------------------------------------- 1 | package employeeinvitation 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | 6 | "github.com/dwarvesf/fortress-api/pkg/model" 7 | ) 8 | 9 | type IStore interface { 10 | Create(db *gorm.DB, employeeOrganization *model.EmployeeInvitation) (*model.EmployeeInvitation, error) 11 | OneByEmployeeID(db *gorm.DB, employeeID string) (*model.EmployeeInvitation, error) 12 | Save(db *gorm.DB, employeeInvitation *model.EmployeeInvitation) error 13 | } 14 | -------------------------------------------------------------------------------- /pkg/store/employeeorganization/interface.go: -------------------------------------------------------------------------------- 1 | package employeeorganization 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | 6 | "github.com/dwarvesf/fortress-api/pkg/model" 7 | ) 8 | 9 | type IStore interface { 10 | Create(db *gorm.DB, employeeOrganization *model.EmployeeOrganization) (*model.EmployeeOrganization, error) 11 | DeleteByEmployeeID(db *gorm.DB, employeeID string) (err error) 12 | } 13 | -------------------------------------------------------------------------------- /pkg/store/employeeposition/interface.go: -------------------------------------------------------------------------------- 1 | package employeeposition 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | 6 | "github.com/dwarvesf/fortress-api/pkg/model" 7 | ) 8 | 9 | type IStore interface { 10 | Create(db *gorm.DB, employeePosition *model.EmployeePosition) (*model.EmployeePosition, error) 11 | DeleteByEmployeeID(db *gorm.DB, employeeID string) (err error) 12 | } 13 | -------------------------------------------------------------------------------- /pkg/store/employeerole/employee_role.go: -------------------------------------------------------------------------------- 1 | package employeerole 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | 6 | "github.com/dwarvesf/fortress-api/pkg/model" 7 | ) 8 | 9 | type store struct { 10 | } 11 | 12 | func New() IStore { 13 | return &store{} 14 | } 15 | 16 | // Create using fore create new Employee role 17 | func (s *store) Create(db *gorm.DB, er *model.EmployeeRole) (*model.EmployeeRole, error) { 18 | return er, db.Create(&er).Error 19 | } 20 | 21 | // HardDeleteByEmployeeID hard delete employeeRole by employeeID 22 | func (s *store) HardDeleteByEmployeeID(db *gorm.DB, employeeID string) error { 23 | return db.Unscoped().Where("employee_id = ?", employeeID).Delete(&model.EmployeeRole{}).Error 24 | } 25 | -------------------------------------------------------------------------------- /pkg/store/employeerole/interface.go: -------------------------------------------------------------------------------- 1 | package employeerole 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | 6 | "github.com/dwarvesf/fortress-api/pkg/model" 7 | ) 8 | 9 | type IStore interface { 10 | Create(db *gorm.DB, er *model.EmployeeRole) (employeeRole *model.EmployeeRole, err error) 11 | HardDeleteByEmployeeID(db *gorm.DB, employeeID string) (err error) 12 | } 13 | -------------------------------------------------------------------------------- /pkg/store/employeestack/employee_stack.go: -------------------------------------------------------------------------------- 1 | package employeestack 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | 6 | "github.com/dwarvesf/fortress-api/pkg/model" 7 | ) 8 | 9 | type store struct{} 10 | 11 | func New() IStore { 12 | return &store{} 13 | } 14 | 15 | // Create create new one by id 16 | func (s *store) Create(db *gorm.DB, employeeStack *model.EmployeeStack) (*model.EmployeeStack, error) { 17 | return employeeStack, db.Create(&employeeStack).Error 18 | } 19 | 20 | // DeleteByEmployeeID delete many EmployeeStaks by employeeID 21 | func (s *store) DeleteByEmployeeID(db *gorm.DB, employeeID string) error { 22 | return db.Unscoped().Where("employee_id = ?", employeeID).Delete(&model.EmployeeStack{}).Error 23 | } 24 | -------------------------------------------------------------------------------- /pkg/store/employeestack/interface.go: -------------------------------------------------------------------------------- 1 | package employeestack 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | 6 | "github.com/dwarvesf/fortress-api/pkg/model" 7 | ) 8 | 9 | type IStore interface { 10 | Create(db *gorm.DB, employeeStack *model.EmployeeStack) (*model.EmployeeStack, error) 11 | DeleteByEmployeeID(db *gorm.DB, employeeID string) error 12 | } 13 | -------------------------------------------------------------------------------- /pkg/store/engagementsrollup/interface.go: -------------------------------------------------------------------------------- 1 | package engagementsrollup 2 | 3 | import ( 4 | "github.com/dwarvesf/fortress-api/pkg/model" 5 | "gorm.io/gorm" 6 | ) 7 | 8 | type IStore interface { 9 | Upsert(db *gorm.DB, record *model.EngagementsRollup) (*model.EngagementsRollup, error) 10 | GetLastMessageID(db *gorm.DB, channelID string) (string, error) 11 | } 12 | -------------------------------------------------------------------------------- /pkg/store/expense/interface.go: -------------------------------------------------------------------------------- 1 | package expense 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | 6 | "github.com/dwarvesf/fortress-api/pkg/model" 7 | ) 8 | 9 | type IStore interface { 10 | Create(db *gorm.DB, e *model.Expense) (*model.Expense, error) 11 | Delete(db *gorm.DB, e *model.Expense) (*model.Expense, error) 12 | Update(db *gorm.DB, e *model.Expense) (*model.Expense, error) 13 | GetValuation(db *gorm.DB, y int) (*model.CurrencyView, error) 14 | GetByQuery(db *gorm.DB, q *ExpenseQuery) (*model.Expense, error) 15 | } 16 | 17 | type ExpenseQuery struct { 18 | BasecampID int 19 | } 20 | -------------------------------------------------------------------------------- /pkg/store/icydistribution/interface.go: -------------------------------------------------------------------------------- 1 | package icydistribution 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | 6 | "github.com/dwarvesf/fortress-api/pkg/model" 7 | ) 8 | 9 | // IStore is an interface for icydistribution store 10 | type IStore interface { 11 | GetWeekly(db *gorm.DB) ([]model.IcyDistribution, error) 12 | } 13 | -------------------------------------------------------------------------------- /pkg/store/icytransaction/icy_transaction.go: -------------------------------------------------------------------------------- 1 | package icytransaction 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | "gorm.io/gorm/clause" 6 | 7 | "github.com/dwarvesf/fortress-api/pkg/model" 8 | ) 9 | 10 | type store struct{} 11 | 12 | func New() IStore { 13 | return &store{} 14 | } 15 | 16 | func (s *store) Create(db *gorm.DB, model []model.IcyTransaction) error { 17 | return db.Clauses(clause.OnConflict{ 18 | Columns: []clause.Column{ 19 | {Name: "sender"}, 20 | {Name: "target"}, 21 | {Name: "category"}, 22 | {Name: "amount"}, 23 | {Name: "txn_time"}, 24 | }, 25 | UpdateAll: true, 26 | }).Create(&model).Error 27 | } 28 | -------------------------------------------------------------------------------- /pkg/store/icytransaction/interface.go: -------------------------------------------------------------------------------- 1 | package icytransaction 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | 6 | "github.com/dwarvesf/fortress-api/pkg/model" 7 | ) 8 | 9 | type IStore interface { 10 | Create(db *gorm.DB, model []model.IcyTransaction) error 11 | } 12 | -------------------------------------------------------------------------------- /pkg/store/inboundfundtransaction/interface.go: -------------------------------------------------------------------------------- 1 | package inboundfundtransaction 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | 6 | "github.com/dwarvesf/fortress-api/pkg/model" 7 | ) 8 | 9 | type IStore interface { 10 | Create(db *gorm.DB, ift *model.InboundFundTransaction) (*model.InboundFundTransaction, error) 11 | DeleteUnpaidByInvoiceID(db *gorm.DB, invoiceID string) error 12 | GetByInvoiceID(db *gorm.DB, invoiceID string) (*model.InboundFundTransaction, error) 13 | Get(db *gorm.DB, q Query) ([]model.InboundFundTransaction, error) 14 | } 15 | -------------------------------------------------------------------------------- /pkg/store/inboundfundtransaction/query.go: -------------------------------------------------------------------------------- 1 | package inboundfundtransaction 2 | 3 | type Query struct { 4 | InvoiceID string 5 | IsPaid bool 6 | } 7 | -------------------------------------------------------------------------------- /pkg/store/invoicenumbercaching/interface.go: -------------------------------------------------------------------------------- 1 | package invoicenumbercaching 2 | 3 | import ( 4 | "time" 5 | 6 | "gorm.io/gorm" 7 | ) 8 | 9 | type IStore interface { 10 | Set(db *gorm.DB, key string) error 11 | Decrease(db *gorm.DB, key string) error 12 | GetNext(db *gorm.DB, key string) (int, error) 13 | 14 | // NextProjectTemplateNumber TODO: (hnh), might be we just need GetNext(key) fn to get these things ? 15 | NextProjectTemplateNumber(db *gorm.DB, pid string) (int, error) 16 | 17 | UpdateInvoiceCachingNumber(db *gorm.DB, issuedAt time.Time, projectAlias string) error 18 | UnCountErrorInvoice(db *gorm.DB, issuedAt time.Time) error 19 | } 20 | -------------------------------------------------------------------------------- /pkg/store/onleaverequest/interface.go: -------------------------------------------------------------------------------- 1 | package onleaverequest 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | 6 | "github.com/dwarvesf/fortress-api/pkg/model" 7 | ) 8 | 9 | type IStore interface { 10 | Create(db *gorm.DB, r *model.OnLeaveRequest) (request *model.OnLeaveRequest, err error) 11 | All(db *gorm.DB, input GetOnLeaveInput) ([]*model.OnLeaveRequest, error) 12 | } 13 | -------------------------------------------------------------------------------- /pkg/store/operationalservice/interface.go: -------------------------------------------------------------------------------- 1 | package operationalservice 2 | 3 | import ( 4 | "time" 5 | 6 | "gorm.io/gorm" 7 | 8 | "github.com/dwarvesf/fortress-api/pkg/model" 9 | ) 10 | 11 | type IStore interface { 12 | FindOperationByMonth(db *gorm.DB, month time.Month) ([]*model.OperationalService, error) 13 | } 14 | -------------------------------------------------------------------------------- /pkg/store/operationalservice/operational_service.go: -------------------------------------------------------------------------------- 1 | package operationalservice 2 | 3 | import ( 4 | "time" 5 | 6 | "gorm.io/gorm" 7 | 8 | "github.com/dwarvesf/fortress-api/pkg/model" 9 | ) 10 | 11 | type store struct{} 12 | 13 | func New() IStore { 14 | return &store{} 15 | } 16 | func (s store) FindOperationByMonth(db *gorm.DB, month time.Month) ([]*model.OperationalService, error) { 17 | var res []*model.OperationalService 18 | query := db.Table("operational_services"). 19 | Preload("Currency"). 20 | Where("is_active is true and type = 'monthly'") 21 | 22 | err := query.Find(&res).Error 23 | if err != nil && err != gorm.ErrRecordNotFound { 24 | return nil, err 25 | } 26 | return res, nil 27 | } 28 | -------------------------------------------------------------------------------- /pkg/store/organization/interface.go: -------------------------------------------------------------------------------- 1 | package organization 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | 6 | "github.com/dwarvesf/fortress-api/pkg/model" 7 | ) 8 | 9 | type IStore interface { 10 | One(db *gorm.DB, id string) (organization *model.Organization, err error) 11 | OneByCode(db *gorm.DB, code string) (organization *model.Organization, err error) 12 | All(db *gorm.DB) ([]*model.Organization, error) 13 | IsExist(db *gorm.DB, id string) (exists bool, err error) 14 | } 15 | -------------------------------------------------------------------------------- /pkg/store/payroll/input.go: -------------------------------------------------------------------------------- 1 | package payroll 2 | 3 | type GetListPayrollInput struct { 4 | ID string 5 | UserID string 6 | Day int 7 | Month int 8 | Year int 9 | } 10 | -------------------------------------------------------------------------------- /pkg/store/permission/interface.go: -------------------------------------------------------------------------------- 1 | package permission 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | 6 | "github.com/dwarvesf/fortress-api/pkg/model" 7 | ) 8 | 9 | type IStore interface { 10 | GetByEmployeeID(db *gorm.DB, employeeID string) (permissions []*model.Permission, err error) 11 | GetByApiKeyID(db *gorm.DB, apiKeyID string) ([]*model.Permission, error) 12 | HasPermission(db *gorm.DB, employeeID string, perm string) (bool, error) 13 | } 14 | -------------------------------------------------------------------------------- /pkg/store/physicalcheckin/interface.go: -------------------------------------------------------------------------------- 1 | package physicalcheckin 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | 6 | "github.com/dwarvesf/fortress-api/pkg/model" 7 | ) 8 | 9 | type IStore interface { 10 | One(db *gorm.DB, id int) (pc *model.PhysicalCheckinTransaction, err error) 11 | Save(db *gorm.DB, pc *model.PhysicalCheckinTransaction) (err error) 12 | GetByEmployeeIDAndDate(db *gorm.DB, employeeID string, date string) (*model.PhysicalCheckinTransaction, error) 13 | } 14 | -------------------------------------------------------------------------------- /pkg/store/position/interface.go: -------------------------------------------------------------------------------- 1 | package position 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | 6 | "github.com/dwarvesf/fortress-api/pkg/model" 7 | ) 8 | 9 | type IStore interface { 10 | All(db *gorm.DB) (positions []*model.Position, err error) 11 | One(db *gorm.DB, id model.UUID) (position *model.Position, err error) 12 | Update(db *gorm.DB, position *model.Position) (p *model.Position, err error) 13 | Create(db *gorm.DB, position *model.Position) (p *model.Position, err error) 14 | Delete(db *gorm.DB, id string) (err error) 15 | } 16 | -------------------------------------------------------------------------------- /pkg/store/project/request.go: -------------------------------------------------------------------------------- 1 | package project 2 | 3 | type GetListProjectInput struct { 4 | Statuses []string `json:"statuses"` 5 | Name string `json:"name"` 6 | Types []string `json:"type"` 7 | AllowsSendingSurvey bool `json:"allowsSendingSurvey"` 8 | } 9 | -------------------------------------------------------------------------------- /pkg/store/projectcommissionconfig/interface.go: -------------------------------------------------------------------------------- 1 | package projectcommissionconfig 2 | 3 | import ( 4 | "github.com/dwarvesf/fortress-api/pkg/model" 5 | "gorm.io/gorm" 6 | ) 7 | 8 | type IStore interface { 9 | GetByProjectID(db *gorm.DB, projectID string) (heads model.ProjectCommissionConfigs, err error) 10 | } 11 | -------------------------------------------------------------------------------- /pkg/store/projectcommissionconfig/project_commission_config.go: -------------------------------------------------------------------------------- 1 | package projectcommissionconfig 2 | 3 | import ( 4 | "github.com/dwarvesf/fortress-api/pkg/model" 5 | "gorm.io/gorm" 6 | ) 7 | 8 | type store struct{} 9 | 10 | func New() IStore { 11 | return &store{} 12 | } 13 | 14 | func (s *store) GetByProjectID(db *gorm.DB, projectID string) (model.ProjectCommissionConfigs, error) { 15 | var heads model.ProjectCommissionConfigs 16 | return heads, db.Where("project_id = ?", projectID).Find(&heads).Error 17 | } 18 | -------------------------------------------------------------------------------- /pkg/store/projectmemberposition/interface.go: -------------------------------------------------------------------------------- 1 | package projectmemberposition 2 | 3 | import ( 4 | "github.com/dwarvesf/fortress-api/pkg/model" 5 | "gorm.io/gorm" 6 | ) 7 | 8 | type IStore interface { 9 | Create(db *gorm.DB, pos ...model.ProjectMemberPosition) error 10 | DeleteByProjectMemberID(db *gorm.DB, memberID string) error 11 | } 12 | -------------------------------------------------------------------------------- /pkg/store/projectslot/interface.go: -------------------------------------------------------------------------------- 1 | package projectslot 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | 6 | "github.com/dwarvesf/fortress-api/pkg/model" 7 | ) 8 | 9 | type IStore interface { 10 | GetPendingSlots(db *gorm.DB, projectID string, preload bool) ([]*model.ProjectSlot, error) 11 | One(db *gorm.DB, id string) (*model.ProjectSlot, error) 12 | Create(db *gorm.DB, slot *model.ProjectSlot) error 13 | Delete(db *gorm.DB, id string) (err error) 14 | 15 | UpdateSelectedFieldsByID(db *gorm.DB, id string, updateModel model.ProjectSlot, updatedFields ...string) (*model.ProjectSlot, error) 16 | UpdateSelectedFieldByProjectID(db *gorm.DB, projectID string, updateModel model.ProjectSlot, updatedField string) error 17 | } 18 | -------------------------------------------------------------------------------- /pkg/store/projectslotposition/interface.go: -------------------------------------------------------------------------------- 1 | package projectslotposition 2 | 3 | import ( 4 | "github.com/dwarvesf/fortress-api/pkg/model" 5 | "gorm.io/gorm" 6 | ) 7 | 8 | type IStore interface { 9 | Create(db *gorm.DB, pos ...model.ProjectSlotPosition) error 10 | DeleteByProjectSlotID(db *gorm.DB, slotID string) error 11 | } 12 | -------------------------------------------------------------------------------- /pkg/store/projectstack/interface.go: -------------------------------------------------------------------------------- 1 | package projectstack 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | 6 | "github.com/dwarvesf/fortress-api/pkg/model" 7 | ) 8 | 9 | type IStore interface { 10 | Create(db *gorm.DB, projectStack *model.ProjectStack) (*model.ProjectStack, error) 11 | DeleteByProjectID(db *gorm.DB, projectID string) (err error) 12 | } 13 | -------------------------------------------------------------------------------- /pkg/store/projectstack/project_stack.go: -------------------------------------------------------------------------------- 1 | package projectstack 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | 6 | "github.com/dwarvesf/fortress-api/pkg/model" 7 | ) 8 | 9 | type store struct{} 10 | 11 | func New() IStore { 12 | return &store{} 13 | } 14 | 15 | // Create create new one by id 16 | func (s *store) Create(db *gorm.DB, projectStack *model.ProjectStack) (*model.ProjectStack, error) { 17 | return projectStack, db.Create(&projectStack).Error 18 | } 19 | 20 | // DeleteByProjectID delete many ProjectStacks by projectID 21 | func (s *store) DeleteByProjectID(db *gorm.DB, projectID string) error { 22 | return db.Unscoped().Where("project_id = ?", projectID).Delete(&model.ProjectStack{}).Error 23 | } 24 | -------------------------------------------------------------------------------- /pkg/store/question/interface.go: -------------------------------------------------------------------------------- 1 | package question 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | 6 | "github.com/dwarvesf/fortress-api/pkg/model" 7 | ) 8 | 9 | type IStore interface { 10 | AllByCategory(db *gorm.DB, category model.EventType, subcategory model.EventSubtype) (questions []*model.Question, err error) 11 | } 12 | -------------------------------------------------------------------------------- /pkg/store/question/question.go: -------------------------------------------------------------------------------- 1 | package question 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | 6 | "github.com/dwarvesf/fortress-api/pkg/model" 7 | ) 8 | 9 | type store struct{} 10 | 11 | func New() IStore { 12 | return &store{} 13 | } 14 | 15 | // AllByCategory get all by category and subcategory 16 | func (s *store) AllByCategory(db *gorm.DB, category model.EventType, subcategory model.EventSubtype) ([]*model.Question, error) { 17 | var questions []*model.Question 18 | return questions, db.Where("category = ? AND subcategory = ?", category, subcategory).Order("\"order\"").Find(&questions).Error 19 | } 20 | -------------------------------------------------------------------------------- /pkg/store/recruitment/interface.go: -------------------------------------------------------------------------------- 1 | package recruitment 2 | 3 | import ( 4 | "time" 5 | 6 | "gorm.io/gorm" 7 | 8 | "github.com/dwarvesf/fortress-api/pkg/model" 9 | ) 10 | 11 | // IStore -- 12 | type IStore interface { 13 | Save(db *gorm.DB, cv *model.Candidate) error 14 | Update(db *gorm.DB, cv *model.Candidate) error 15 | GetByBasecampID(db *gorm.DB, bcID int) (*model.Candidate, error) 16 | GetApproachCandidateByBasecampID(db *gorm.DB, bcID int) (*model.Candidate, error) 17 | GetByDuration(db *gorm.DB, from, to time.Time) ([]model.Candidate, error) 18 | GetAll(db *gorm.DB) ([]model.Candidate, error) 19 | GetOffered(db *gorm.DB, batchDate, dueDate time.Time) ([]model.Candidate, error) 20 | } 21 | -------------------------------------------------------------------------------- /pkg/store/role/interface.go: -------------------------------------------------------------------------------- 1 | package role 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | 6 | "github.com/dwarvesf/fortress-api/pkg/model" 7 | ) 8 | 9 | type IStore interface { 10 | All(db *gorm.DB) (roles []*model.Role, err error) 11 | One(db *gorm.DB, id model.UUID) (role *model.Role, err error) 12 | GetByLevel(db *gorm.DB, level int64) ([]*model.Role, error) 13 | GetByCode(db *gorm.DB, code string) (*model.Role, error) 14 | GetByIDs(db *gorm.DB, ids []model.UUID) ([]*model.Role, error) 15 | IsExist(db *gorm.DB, id string) (exists bool, err error) 16 | } 17 | -------------------------------------------------------------------------------- /pkg/store/salaryadvance/interface.go: -------------------------------------------------------------------------------- 1 | package salaryadvance 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | 6 | "github.com/dwarvesf/fortress-api/pkg/model" 7 | ) 8 | 9 | type IStore interface { 10 | One(db *gorm.DB, id string) (salaryAdvance *model.SalaryAdvance, err error) 11 | ListNotPayBackByEmployeeID(db *gorm.DB, employeeID string) (salaryAdvance []model.SalaryAdvance, err error) 12 | Save(db *gorm.DB, salaryAdvance *model.SalaryAdvance) (err error) 13 | ListAggregatedSalaryAdvance(db *gorm.DB, idPaid *bool, paging model.Pagination, order model.SortOrder) (report []model.AggregatedSalaryAdvance, err error) 14 | TotalAggregatedSalaryAdvance(db *gorm.DB, idPaid *bool) (count, totalIcy int64, totalUSD float64, err error) 15 | } 16 | -------------------------------------------------------------------------------- /pkg/store/schedule/interface.go: -------------------------------------------------------------------------------- 1 | package schedule 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | 6 | "github.com/dwarvesf/fortress-api/pkg/model" 7 | ) 8 | 9 | type IStore interface { 10 | Create(db *gorm.DB, schedule *model.Schedule) (*model.Schedule, error) 11 | CreateDiscord(db *gorm.DB, schedule *model.ScheduleDiscordEvent) (*model.ScheduleDiscordEvent, error) 12 | GetOneByGcalID(db *gorm.DB, gcalID string) (*model.Schedule, error) 13 | 14 | Update(db *gorm.DB, schedule *model.Schedule) (*model.Schedule, error) 15 | } 16 | -------------------------------------------------------------------------------- /pkg/store/seniority/interface.go: -------------------------------------------------------------------------------- 1 | package seniority 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | 6 | "github.com/dwarvesf/fortress-api/pkg/model" 7 | ) 8 | 9 | type IStore interface { 10 | All(db *gorm.DB) ([]*model.Seniority, error) 11 | One(db *gorm.DB, id model.UUID) (seniorities *model.Seniority, err error) 12 | IsExist(db *gorm.DB, id string) (bool, error) 13 | } 14 | -------------------------------------------------------------------------------- /pkg/store/socialaccount/interface.go: -------------------------------------------------------------------------------- 1 | package socialaccount 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | 6 | "github.com/dwarvesf/fortress-api/pkg/model" 7 | ) 8 | 9 | type IStore interface { 10 | Create(db *gorm.DB, sa *model.SocialAccount) (account *model.SocialAccount, err error) 11 | Update(db *gorm.DB, sa *model.SocialAccount) (account *model.SocialAccount, err error) 12 | GetByEmployeeID(db *gorm.DB, employeeID string) (accounts []*model.SocialAccount, err error) 13 | GetByType(db *gorm.DB, saType string) (accounts []model.SocialAccount, err error) 14 | UpdateSelectedFieldsByID(db *gorm.DB, id string, updateModel model.SocialAccount, updatedFields ...string) (*model.SocialAccount, error) 15 | } 16 | -------------------------------------------------------------------------------- /pkg/store/stack/interface.go: -------------------------------------------------------------------------------- 1 | package stack 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | 6 | "github.com/dwarvesf/fortress-api/pkg/model" 7 | ) 8 | 9 | type IStore interface { 10 | All(db *gorm.DB, keyword string, pagination *model.Pagination) (int64, []*model.Stack, error) 11 | One(db *gorm.DB, id string) (*model.Stack, error) 12 | GetByIDs(db *gorm.DB, ids []model.UUID) (stacks []*model.Stack, err error) 13 | Update(db *gorm.DB, stack *model.Stack) (s *model.Stack, err error) 14 | Create(db *gorm.DB, stack *model.Stack) (s *model.Stack, err error) 15 | Delete(db *gorm.DB, id string) (err error) 16 | } 17 | -------------------------------------------------------------------------------- /pkg/store/test_repo.go: -------------------------------------------------------------------------------- 1 | package store 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | ) 6 | 7 | // testRepo is implementation of repository 8 | type testRepo struct { 9 | Database *gorm.DB 10 | } 11 | 12 | // DB database connection 13 | func (s *testRepo) DB() *gorm.DB { 14 | return s.Database 15 | } 16 | 17 | func NewTestRepo(db *gorm.DB) DBRepo { 18 | return &testRepo{Database: db} 19 | } 20 | 21 | // NewTransaction for database connection 22 | func (s *testRepo) NewTransaction() (newRepo DBRepo, finallyFn FinallyFunc) { 23 | finallyFn = func(err error) error { 24 | return err 25 | } 26 | 27 | return &testRepo{Database: s.DB()}, finallyFn 28 | } 29 | 30 | func (s *testRepo) SetNewDB(db *gorm.DB) { 31 | s.Database = db 32 | } 33 | -------------------------------------------------------------------------------- /pkg/store/workunit/interface.go: -------------------------------------------------------------------------------- 1 | package workunit 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | 6 | "github.com/dwarvesf/fortress-api/pkg/model" 7 | ) 8 | 9 | type IStore interface { 10 | Create(db *gorm.DB, workUnit *model.WorkUnit) error 11 | GetByProjectID(db *gorm.DB, projectID string, status model.WorkUnitStatus) (workUnits []*model.WorkUnit, err error) 12 | One(db *gorm.DB, id string) (*model.WorkUnit, error) 13 | IsExists(db *gorm.DB, id string) (bool, error) 14 | UpdateSelectedFieldsByID(db *gorm.DB, id string, updateModel model.WorkUnit, updatedFields ...string) (workUnit *model.WorkUnit, err error) 15 | GetAllWorkUnitByEmployeeID(db *gorm.DB, employeeID string) (workUnits []*model.WorkUnit, err error) 16 | } 17 | -------------------------------------------------------------------------------- /pkg/store/workunitstack/interface.go: -------------------------------------------------------------------------------- 1 | package workunitstack 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | 6 | "github.com/dwarvesf/fortress-api/pkg/model" 7 | ) 8 | 9 | type IStore interface { 10 | Create(db *gorm.DB, wus *model.WorkUnitStack) error 11 | DeleteByWorkUnitID(db *gorm.DB, workUnitID string) error 12 | } 13 | -------------------------------------------------------------------------------- /pkg/store/workunitstack/work_unit_stack.go: -------------------------------------------------------------------------------- 1 | package workunitstack 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | 6 | "github.com/dwarvesf/fortress-api/pkg/model" 7 | ) 8 | 9 | type store struct{} 10 | 11 | func New() IStore { 12 | return &store{} 13 | } 14 | 15 | // Create create new WorkUnitStack 16 | func (s *store) Create(db *gorm.DB, wus *model.WorkUnitStack) error { 17 | return db.Create(&wus).Error 18 | } 19 | 20 | // DeleteByWorkUnitID delete many workUnitStack by workUnitID 21 | func (s *store) DeleteByWorkUnitID(db *gorm.DB, workUnitID string) error { 22 | return db.Unscoped().Where("work_unit_id = ?", workUnitID).Delete(&model.WorkUnitStack{}).Error 23 | } 24 | -------------------------------------------------------------------------------- /pkg/templates/assets/fonts/AvenirNext-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dwarvesf/fortress-api/86623ffbd0497624a19056e7d00c32ff2d0a39d0/pkg/templates/assets/fonts/AvenirNext-Bold.woff -------------------------------------------------------------------------------- /pkg/templates/assets/fonts/AvenirNext-BoldItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dwarvesf/fortress-api/86623ffbd0497624a19056e7d00c32ff2d0a39d0/pkg/templates/assets/fonts/AvenirNext-BoldItalic.woff -------------------------------------------------------------------------------- /pkg/templates/assets/fonts/AvenirNext-DemiBold.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dwarvesf/fortress-api/86623ffbd0497624a19056e7d00c32ff2d0a39d0/pkg/templates/assets/fonts/AvenirNext-DemiBold.eot -------------------------------------------------------------------------------- /pkg/templates/assets/fonts/AvenirNext-DemiBold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dwarvesf/fortress-api/86623ffbd0497624a19056e7d00c32ff2d0a39d0/pkg/templates/assets/fonts/AvenirNext-DemiBold.woff -------------------------------------------------------------------------------- /pkg/templates/assets/fonts/AvenirNext-DemiBoldItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dwarvesf/fortress-api/86623ffbd0497624a19056e7d00c32ff2d0a39d0/pkg/templates/assets/fonts/AvenirNext-DemiBoldItalic.woff -------------------------------------------------------------------------------- /pkg/templates/assets/fonts/AvenirNext-Heavy.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dwarvesf/fortress-api/86623ffbd0497624a19056e7d00c32ff2d0a39d0/pkg/templates/assets/fonts/AvenirNext-Heavy.woff -------------------------------------------------------------------------------- /pkg/templates/assets/fonts/AvenirNext-HeavyItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dwarvesf/fortress-api/86623ffbd0497624a19056e7d00c32ff2d0a39d0/pkg/templates/assets/fonts/AvenirNext-HeavyItalic.woff -------------------------------------------------------------------------------- /pkg/templates/assets/fonts/AvenirNext-Italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dwarvesf/fortress-api/86623ffbd0497624a19056e7d00c32ff2d0a39d0/pkg/templates/assets/fonts/AvenirNext-Italic.woff -------------------------------------------------------------------------------- /pkg/templates/assets/fonts/AvenirNext-Medium.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dwarvesf/fortress-api/86623ffbd0497624a19056e7d00c32ff2d0a39d0/pkg/templates/assets/fonts/AvenirNext-Medium.woff -------------------------------------------------------------------------------- /pkg/templates/assets/fonts/AvenirNext-MediumItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dwarvesf/fortress-api/86623ffbd0497624a19056e7d00c32ff2d0a39d0/pkg/templates/assets/fonts/AvenirNext-MediumItalic.woff -------------------------------------------------------------------------------- /pkg/templates/assets/fonts/AvenirNext-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dwarvesf/fortress-api/86623ffbd0497624a19056e7d00c32ff2d0a39d0/pkg/templates/assets/fonts/AvenirNext-Regular.woff -------------------------------------------------------------------------------- /pkg/utils/errors.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "errors" 5 | ) 6 | 7 | var ( 8 | ErrInvalidToken = errors.New("token expired, please log out and log in again") 9 | ErrInvalidSignature = errors.New("invalid signature") 10 | ErrBadToken = errors.New("bad token") 11 | ErrAuthenticationTypeHeaderInvalid = errors.New("authentication type header is invalid") 12 | ErrUnexpectedAuthorizationHeader = errors.New("unexpected authorization headers") 13 | ErrInvalidUUID = errors.New("invalid UUID") 14 | ) 15 | -------------------------------------------------------------------------------- /pkg/utils/testhelper/db_test.go: -------------------------------------------------------------------------------- 1 | package testhelper 2 | 3 | import ( 4 | "testing" 5 | 6 | _ "github.com/lib/pq" 7 | "github.com/stretchr/testify/require" 8 | ) 9 | 10 | func TestLoadFixture(t *testing.T) { 11 | tests := []struct { 12 | name string 13 | }{ 14 | { 15 | name: "success", 16 | }, 17 | } 18 | for _, tt := range tests { 19 | t.Run(tt.name, func(t *testing.T) { 20 | require.NotNil(t, LoadTestDB()) 21 | }) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /pkg/view/asset.go: -------------------------------------------------------------------------------- 1 | package view 2 | 3 | type ContentData struct { 4 | Url string `json:"url"` 5 | } // @name ContentData 6 | 7 | // ContentDataResponse represent the content data 8 | type ContentDataResponse struct { 9 | Data *ContentData `json:"data"` 10 | } // @name ContentDataResponse 11 | 12 | func ToContentData(url string) *ContentData { 13 | return &ContentData{ 14 | Url: url, 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /pkg/view/company_info.go: -------------------------------------------------------------------------------- 1 | package view 2 | 3 | import "github.com/dwarvesf/fortress-api/pkg/model" 4 | 5 | func ToCompanyInfos(companies []*model.CompanyInfo) []CompanyInfo { 6 | rs := make([]CompanyInfo, 0, len(companies)) 7 | for _, com := range companies { 8 | c := ToCompanyInfo(com) 9 | if c != nil { 10 | rs = append(rs, *c) 11 | } 12 | } 13 | 14 | return rs 15 | } 16 | 17 | type GetListCompanyInfoResponse struct { 18 | Data []*CompanyInfo `json:"data"` 19 | } // @name GetListCompanyInfoResponse 20 | -------------------------------------------------------------------------------- /pkg/view/hiring.go: -------------------------------------------------------------------------------- 1 | package view 2 | 3 | import "github.com/dwarvesf/fortress-api/pkg/model" 4 | 5 | type HiringResponse struct { 6 | Data []model.NotionHiringPosition `json:"data"` 7 | } 8 | -------------------------------------------------------------------------------- /pkg/view/pagination.go: -------------------------------------------------------------------------------- 1 | package view 2 | 3 | type Pagination struct { 4 | Page int64 `json:"page" form:"page,default=0"` // page index 5 | Size int64 `json:"size" form:"size"` // page size 6 | Sort string `json:"sort" form:"sort" swaggerignore:"true"` // sort field 7 | } // @name Pagination 8 | -------------------------------------------------------------------------------- /pkg/view/pagination_view.go: -------------------------------------------------------------------------------- 1 | package view 2 | 3 | type PaginationResponse struct { 4 | Pagination 5 | Total int64 `json:"total"` 6 | } // @name PaginationResponse 7 | -------------------------------------------------------------------------------- /pkg/view/seniority.go: -------------------------------------------------------------------------------- 1 | package view 2 | 3 | import "github.com/dwarvesf/fortress-api/pkg/model" 4 | 5 | type Seniority struct { 6 | ID string `json:"id"` 7 | Code string `json:"code"` 8 | Name string `json:"name"` 9 | } // @name Seniority 10 | 11 | func ToSeniority(seniority model.Seniority) Seniority { 12 | return Seniority{ 13 | ID: seniority.ID.String(), 14 | Code: seniority.Code, 15 | Name: seniority.Name, 16 | } 17 | } 18 | --------------------------------------------------------------------------------