diff --git a/README.md b/README.md index 93807df..2a7b440 100644 --- a/README.md +++ b/README.md @@ -17,11 +17,11 @@ This clicker bot combines fun and strategy, making it a unique experience for Te Our project leverages a modern technology stack to ensure scalability, performance, and seamless user interactions: -- **Frontend**: [React.js, Vue.js, etc.] +- **Frontend**: [React, Typescript] - **Backend**: [Django, Flask, etc.] -- **Database**: [PostgreSQL, MongoDB, MySQL, etc.] +- **Database**: [PostgreSQL] - **Authentication**: [JWT, OAuth, etc.] -- **Deployment**: [Docker, Kubernetes, AWS, etc.] +- **Deployment**: [Docker] We have structured our architecture for flexibility and ease of integration with future features. @@ -29,9 +29,9 @@ We have structured our architecture for flexibility and ease of integration with The project is a collaboration of skilled and passionate individuals: -2. **Michael Kostochka**: [Role: Backend Developer] - Ensures smooth operations behind the scenes with efficient APIs. -3. **Sitnikov Arseniy**: [Role: Database Architect] - Responsible for managing data flows and ensuring high performance. -4. **Vakulenkov Danila**: [Role: DevOps Engineer] - Orchestrates deployment, monitoring, and infrastructure management. +2. **Michael Kostochka**: [Role: Backend Developer, Database Architect] +3. **Sitnikov Arseniy**: [Role: Frontend Developer, Database Architect] +4. **Vakulenkov Danila**: [Role: Backend Engineer, Database Architect] ## 🎨 **Visuals** @@ -49,51 +49,22 @@ git clone https://github.com/Danya-Djan/db_kyc_project.git cd db_kyc_project ``` -### **2. Install Dependencies** +### **2. Environment Setup** -Ensure you have [Node.js](https://nodejs.org/) and [Docker](https://www.docker.com/) installed. +Create a `.env` file in the root of the project and add the needed variables -For **Frontend**: - -```bash -cd frontend -``` - -For **Backend**: - -```bash -cd backend -``` - -### **3. Environment Setup** - -Create a `.env` file in the root of the project and add the following variables: - -``` -DB_HOST=localhost -DB_USER=[your-db-user] -DB_PASS=[your-db-password] -JWT_SECRET=[your-secret] -``` - -### **4. Run the Project** +### **3. Run the Project** To start both frontend and backend servers in development mode: For **Frontend and Backend**: ```bash -docker-compose up +docker-compose up --build ``` -You can access the application at `http://localhost:3000`. - -## 🀝 **Contributing** - -We welcome contributions! Please read our [CONTRIBUTING.md](link_to_contributing_file) for details on our code of conduct and the process for submitting pull requests. - ## πŸ“œ **License** -This project is licensed under the [MIPT License](link_to_license_file). +This project is licensed under the [MIPT License](https://github.com/MIPT-ILab/MDSP/blob/master/LICENSE). --- \ No newline at end of file diff --git a/backend/auction/admin.py b/backend/auction/admin.py index 21e50de..adf954c 100644 --- a/backend/auction/admin.py +++ b/backend/auction/admin.py @@ -44,26 +44,26 @@ class AuctionAdmin(admin.ModelAdmin): def view_product_link(self, obj): url = reverse("admin:auction_product_change", args=[obj.product_id]) - return format_html(f'{obj.product.name} ({obj.product_id})') + return format_html('{} ({})', url, obj.product.name, obj.product_id) view_product_link.short_description = 'Π’ΠΎΠ²Π°Ρ€' def view_betters_link(self, obj): count = obj.betters.distinct().count() url = reverse('admin:users_tguser_changelist') + '?' + urlencode({'betters__pk': f'{obj.pk}'}) - return format_html(f' {count} users ') + return format_html(' {} users ', url, count) view_betters_link.short_description = 'ΠŸΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΠΈ, сдСлавшиС ставки' def view_bets_link(self, obj): count = obj.bets.count() url = reverse('admin:auction_bet_changelist') + '?' + urlencode({'auction_id': f'{obj.pk}'}) - return format_html(f' {count} bets ') + return format_html(' {} bets ', url, count) view_bets_link.short_description = 'Π‘Ρ‚Π°Π²ΠΊΠΈ' def view_winners_link(self, obj): winning_user_ids = obj.bets.filter(_is_winning=True).values_list('user_id', flat=True) count = winning_user_ids.count() url = reverse('admin:users_tguser_changelist') + '?' + urlencode({'pk__in': ','.join(map(str, winning_user_ids))}) - return format_html(f' {count} ΠΏΠΎΠ±Π΅Π΄ΠΈΡ‚Π΅Π»Π΅ΠΉ ') + return format_html(' {} ΠΏΠΎΠ±Π΅Π΄ΠΈΡ‚Π΅Π»Π΅ΠΉ ', url, count) view_winners_link.short_description = 'ΠŸΠΎΠ±Π΅Π΄ΠΈΡ‚Π΅Π»ΠΈ' @@ -86,7 +86,7 @@ class ProductAdmin(admin.ModelAdmin): def view_auctions_link(self, obj): count = obj.auctions.count() url = reverse('admin:auction_auction_changelist') + '?' + urlencode({'product_id': f'{obj.pk}'}) - return format_html(f' {count} auctions ') + return format_html(' {} auctions ', url, count) view_auctions_link.short_description = 'Аукционы' @@ -132,16 +132,16 @@ class BetAdmin(admin.ModelAdmin): def view_user_link(self, obj): url = reverse("admin:users_tguser_change", args=[obj.user_id]) - return format_html(f'{obj.user}') + return format_html('{}', url, obj.user) view_user_link.short_description = 'ΠŸΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒ' def view_auction_link(self, obj): url = reverse("admin:auction_auction_change", args=[obj.auction_id]) - return format_html(f'{obj.auction}') + return format_html('{}', url, obj.auction) view_auction_link.short_description = 'Аукцион' def view_transactions_link(self, obj): count = obj.transactions.count() url = reverse('admin:users_bettransaction_changelist') + '?' + urlencode({'bet_id': f'{obj.pk}'}) - return format_html(f' {count} transactions ') + return format_html(' {} transactions ', url, count) view_transactions_link.short_description = 'Π’Ρ€Π°Π½Π·Π°ΠΊΡ†ΠΈΠΈ' diff --git a/backend/clicks/admin.py b/backend/clicks/admin.py index 4657d44..2b1add1 100644 --- a/backend/clicks/admin.py +++ b/backend/clicks/admin.py @@ -28,10 +28,10 @@ class ClickAdmin(admin.ModelAdmin): def view_user_link(self, obj): url = reverse("admin:users_tguser_change", args=[obj.user_id]) - return format_html(f'{obj.user}') + return format_html('{}', url, obj.user) view_user_link.short_description = 'ΠŸΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒ' def view_transaction_link(self, obj): url = reverse("admin:users_clicktransaction_change", args=[obj.transaction.id]) - return format_html(f'{obj.transaction}') + return format_html('{}', url, obj.transaction) view_transaction_link.short_description = 'Вранзакция' diff --git a/backend/users/admin.py b/backend/users/admin.py index c0ec8ec..8acefbf 100644 --- a/backend/users/admin.py +++ b/backend/users/admin.py @@ -58,20 +58,20 @@ class TGUserAdmin(admin.ModelAdmin): def view_user_link(self, obj): url = reverse("admin:auth_user_change", args=[obj.user_id]) - return format_html(f'{obj.user.username} ({obj.user_id})') + return format_html('{} ({})', url, obj.user.username, obj.user_id) view_user_link.short_description = 'БистСмный ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒ' def view_referred_by_link(self, obj): if not obj.referred_by: return url = reverse("admin:users_tguser_change", args=[obj.referred_by.tg_id]) - return format_html(f'{obj.referred_by.username} ({obj.referred_by.tg_id})') + return format_html('{} ({})', url, obj.referred_by.username, obj.referred_by.tg_id) view_referred_by_link.short_description = 'КСм Π±Ρ‹Π» ΠΏΡ€ΠΈΠ³Π»Π°ΡˆΠ΅Π½' def view_referred_users_link(self, obj): count = obj.referrees.count() url = reverse('admin:users_tguser_changelist') + '?' + urlencode({'referred_by__tg_id': f'{obj.tg_id}'}) - return format_html(f' {count} users ') + return format_html(' {} users ', url, count) view_referred_users_link.short_description = 'ΠŸΡ€ΠΈΠ³Π»Π°ΡˆΠ΅Π½Π½Ρ‹Π΅ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΠΈ' def view_transactions(self, obj): @@ -82,26 +82,25 @@ class TGUserAdmin(admin.ModelAdmin): referral_url = reverse('admin:users_referraltransaction_changelist') + '?' + urlencode({'user_id': f'{obj.tg_id}'}) return format_html( - f' всС // ' - f' ΠΊΠ»ΠΈΠΊΠΈ // ' - f' ставки // ' - f' комиссии // ' - f' Ρ€Π΅Ρ„Π΅Ρ€Π°Π»ΡŒΠ½Π°Ρ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ° ' + ' всС // ' + ' ΠΊΠ»ΠΈΠΊΠΈ // ' + ' ставки // ' + ' комиссии // ' + ' Ρ€Π΅Ρ„Π΅Ρ€Π°Π»ΡŒΠ½Π°Ρ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ° ', + all_url, click_url, bet_url, commission_url, referral_url ) view_transactions.short_description = 'Π’Ρ€Π°Π½Π·Π°ΠΊΡ†ΠΈΠΈ' def view_clicks_link(self, obj): count = obj.clicks.count() url = reverse('admin:clicks_click_changelist') + '?' + urlencode({'user_id': f'{obj.tg_id}'}) - return format_html(f' {count} clicks ') + return format_html(' {} clicks ', url, count) view_clicks_link.short_description = 'Клики' @admin.action(description="Π‘ΠΎΠ·Π΄Π°Ρ‚ΡŒ рассылку для Π²Ρ‹Π±Ρ€Π°Π½Π½Ρ‹Ρ… ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Π΅ΠΉ") def create_mailing_list(self, request, queryset): request.session['user_ids'] = list(queryset.values_list('pk', flat=True)) - return HttpResponseRedirect( - f'/admin/users/mailinglist/add/' - ) + return HttpResponseRedirect(reverse('admin:users_mailinglist_add')) class MailingListAdminForm(forms.ModelForm): @@ -162,14 +161,14 @@ class MailingListReceiverInfoAdmin(admin.ModelAdmin): if not obj.user: return None link = reverse("admin:users_tguser_change", args=[obj.user.tg_id]) - return format_html(f'{obj.user}') + return format_html('{}', link, obj.user) view_user_link.short_description = 'ΠŸΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒ' def view_mailing_list_link(self, obj): if not obj.mailing_list: return None link = reverse("admin:users_mailinglist_change", args=[obj.mailing_list.pk]) - return format_html(f'{obj.mailing_list}') + return format_html('{}', link, obj.mailing_list) view_mailing_list_link.short_description = 'Рассылка' @@ -205,28 +204,28 @@ class MailingListAdmin(admin.ModelAdmin): count = obj.users.count() url = reverse('admin:users_tguser_changelist') + '?' + urlencode( {'mailing_lists__id': f'{obj.id}'}) - return format_html(f' {count} ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Π΅ΠΉ ') + return format_html(' {} ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Π΅ΠΉ ', url, count) view_users_link.short_description = 'ΠŸΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΠΈ' def view_mailing_list_receiver_infos_link(self, obj): count = obj.mailing_list_receiver_infos.count() url = reverse('admin:users_mailinglistreceiverinfo_changelist') + '?' + urlencode( {'mailing_list_id': f'{obj.id}'}) - return format_html(f' {count} ΠΏΠΎΠ»ΡƒΡ‡Π°Ρ‚Π΅Π»Π΅ΠΉ ') + return format_html(' {} ΠΏΠΎΠ»ΡƒΡ‡Π°Ρ‚Π΅Π»Π΅ΠΉ ', url, count) view_mailing_list_receiver_infos_link.short_description = 'Π˜Π½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΡ ΠΎ получатСлях' def view_main_button_link(self, obj): if not obj.main_button: return url = reverse("admin:misc_button_change", args=[obj.main_button_id]) - return format_html(f' Кнопка β„–{obj.main_button_id}') + return format_html(' Кнопка β„–{}', url, obj.main_button_id) view_main_button_link.short_description = 'Основная ΠΊΠ½ΠΎΠΏΠΊΠ°' def view_webapp_button_link(self, obj): if not obj.webapp_button: return url = reverse("admin:misc_button_change", args=[obj.webapp_button_id]) - return format_html(f' Кнопка β„–{obj.webapp_button_id}') + return format_html(' Кнопка β„–{}', url, obj.webapp_button_id) view_webapp_button_link.short_description = 'Кнопка, ΠΎΡ‚ΠΊΡ€Ρ‹Π²Π°ΡŽΡ‰Π°Ρ Π²Π΅Π±Π°ΠΏΠΏ' @@ -242,7 +241,7 @@ class TransactionChildAdmin(PolymorphicChildModelAdmin): if not obj.user: return url = reverse("admin:users_tguser_change", args=[obj.user.tg_id]) - return format_html(f'{obj.user}') + return format_html('{}', url, obj.user) view_user_link.short_description = 'ΠŸΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒ' def has_delete_permission(self, request, obj=None): @@ -269,7 +268,7 @@ class ClickTransactionAdmin(TransactionChildAdmin): def view_click_link(self, obj): link = reverse("admin:clicks_click_change", args=[obj.click_id]) - return format_html(f' {obj.click}') + return format_html(' {}', link, obj.click) view_click_link.short_description = 'Клик' @@ -293,7 +292,7 @@ class BetTransactionAdmin(TransactionChildAdmin): def view_bet_link(self, obj): link = reverse("admin:auction_bet_change", args=[obj.bet_id]) - return format_html(f'{obj.bet}') + return format_html('{}', link, obj.bet) view_bet_link.short_description = 'Π‘Ρ‚Π°Π²ΠΊΠ°' def view_commission_link(self, obj): @@ -302,7 +301,7 @@ class BetTransactionAdmin(TransactionChildAdmin): except ObjectDoesNotExist: return None link = reverse("admin:users_commissiontransaction_change", args=[obj.commission.id]) - return format_html(f' {obj.commission} ') + return format_html(' {} ', link, obj.commission) view_commission_link.short_description = 'Комиссия' def view_refunded_by_link(self, obj): @@ -311,14 +310,14 @@ class BetTransactionAdmin(TransactionChildAdmin): except ObjectDoesNotExist: return None link = reverse("admin:users_bettransaction_change", args=[obj.refunded_by.id]) - return format_html(f' {obj.refunded_by} ') + return format_html(' {} ', link, obj.refunded_by) view_refunded_by_link.short_description = 'Π§Π΅ΠΌ компСнсирована' def view_refund_to_link(self, obj): if not obj.refund_to: return None link = reverse("admin:users_bettransaction_change", args=[obj.refund_to_id]) - return format_html(f' {obj.refund_to} ') + return format_html(' {} ', link, obj.refund_to) view_refund_to_link.short_description = 'Π§Ρ‚ΠΎ компСнсируСт' @@ -339,7 +338,7 @@ class CommissionTransactionAdmin(TransactionChildAdmin): def view_bet_transaction_link(self, obj): link = reverse("admin:users_bettransaction_change", args=[obj.parent_transaction]) - return format_html(f' {obj.parent_transaction} ') + return format_html(' {} ', link, obj.parent_transaction) view_bet_transaction_link.short_description = 'Π ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΡΠΊΠ°Ρ транзакция' @@ -389,7 +388,7 @@ class TransactionParentAdmin(PolymorphicParentModelAdmin): if not obj.user: return url = reverse("admin:users_tguser_change", args=[obj.user.tg_id]) - return format_html(f'{obj.user}') + return format_html('{}', url, obj.user) view_user_link.short_description = 'ΠŸΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒ' def view_type(self, obj):