Passed
Pull Request — master (#117)
by
unknown
05:28
created

keyboard   F

Complexity

Total Complexity 60

Size/Duplication

Total Lines 419
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 60
eloc 314
dl 0
loc 419
rs 3.6
c 0
b 0
f 0

26 Methods

Rating   Name   Duplication   Size   Complexity  
A Keyboards.__init__() 0 2 1
A Keyboards.generate_local_chat_prefs() 0 16 2
B Keyboards.generate_global_chat_prefs() 0 31 6
A Keyboards.configure_chat() 0 25 3
A Keyboards.generate_main_menu() 0 20 3
A Keyboards.fin_category_menu() 0 13 1
A Keyboards.empty() 0 7 1
A Keyboards.generate_mailings_keyboard() 0 18 4
A Keyboards.generate_chat_prefs() 0 15 1
A Keyboards.finances_main() 0 18 4
A Keyboards.reg_chat() 0 17 5
A Keyboards.cancel() 0 8 1
A Keyboards.generate_available_chat_types() 0 13 3
A Keyboards.generate_finances_prompt() 0 5 1
A Keyboards.generate_names_selector() 0 12 2
A Keyboards.prompt() 0 21 3
A Keyboards.inline_unsubscribe() 0 8 1
A Keyboards.generate_mailing_mgmt() 0 23 2
A Keyboards.generate_administrating_groups() 0 14 4
A Keyboards.generate_prefs_keyboard() 0 14 1
A Keyboards.generate_schedule_keyboard() 0 20 1
A Keyboards.generate_alphabet_keyboard() 0 14 3
A Keyboards.skip() 0 8 1
A Keyboards.generate_call_prompt() 0 8 1
A Keyboards.generate_names_keyboard() 0 19 4
A Keyboards.fin_prefs() 0 12 1

How to fix   Complexity   

Complexity

Complex classes like keyboard often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
import os
2
3
from vk_api.keyboard import VkKeyboard
4
5
from database import Database
6
7
8
class Keyboards:
9
    """
10
    Класс с генераторами пользовательских клавиатур
11
    """
12
13
    def __init__(self):
14
        self.db = Database(os.environ["DATABASE_URL"])
15
16
    @staticmethod
17
    def generate_main_menu(is_admin: bool):
18
        """
19
        Генерирует клавиатуру с главным меню
20
        """
21
        kb = VkKeyboard()
22
        if is_admin:
23
            kb.add_button(label="Призыв", payload={"button": "call"})
24
            kb.add_button(label="Финансы", payload={"button": "finances"})
25
            kb.add_line()
26
        kb.add_button(label="Расписание", payload={"button": "schedule"})
27
        kb.add_line()
28
        kb.add_button(
29
            label="Управление рассылками", payload={"button": "mailings"},
30
        )
31
        if is_admin:
32
            kb.add_line()
33
            kb.add_button(label="Настройки", payload={"button": "prefs"})
34
            kb.add_button(label="Веб", payload={"button": "web"})
35
        return kb.get_keyboard()
36
37
    @staticmethod
38
    def generate_schedule_keyboard():
39
        """
40
        Возвращает клавиатуру с выбором даты получения расписания
41
        """
42
        kb = VkKeyboard()
43
        kb.add_button(label="На сегодня", payload={"button": "today"})
44
        kb.add_button(label="На завтра", payload={"button": "tomorrow"})
45
        kb.add_line()
46
        kb.add_button(
47
            label="На послезавтра", payload={"button": "day_after_tomorrow"},
48
        )
49
        kb.add_button(
50
            label="Выбрать дату", payload={"button": "arbitrary"},
51
        )
52
        kb.add_line()
53
        kb.add_button(
54
            label="Назад", payload={"button": "home"},
55
        )
56
        return kb.get_keyboard()
57
58
    @staticmethod
59
    def empty():
60
        """
61
        Возвращает пустую клавиатуру
62
        """
63
        kb = VkKeyboard()
64
        return kb.get_empty_keyboard()
65
66
    @staticmethod
67
    def skip():
68
        """
69
        Возвращает клавиатуру с кнопкой "Пропустить"
70
        """
71
        kb = VkKeyboard()
72
        kb.add_button(label="Пропустить", payload={"button": "skip"})
73
        return kb.get_keyboard()
74
75
    @staticmethod
76
    def cancel():
77
        """
78
        Возвращает клавиатуру с кнопкой "Отмена"
79
        """
80
        kb = VkKeyboard()
81
        kb.add_button(label="Отмена", payload={"button": "cancel"})
82
        return kb.get_keyboard()
83
84
    @staticmethod
85
    def generate_prefs_keyboard():
86
        """
87
        Возвращает клавиатуру с настройками бота
88
        """
89
        kb = VkKeyboard()
90
        kb.add_button(label="Чаты", payload={"button": "chats"})
91
        kb.add_line()
92
        kb.add_button(label="Использование имён в призыве", payload={"button": "names"})
93
        kb.add_line()
94
        kb.add_button(
95
            label="Назад", payload={"button": "home"},
96
        )
97
        return kb.get_keyboard()
98
99
    @staticmethod
100
    def generate_chat_prefs():
101
        kb = VkKeyboard()
102
        kb.add_button(
103
            label="Глобальные настройки чатов", payload={"button": "global_chat"}
104
        )
105
        kb.add_line()
106
        kb.add_button(
107
            label="Локальные настройки чатов", payload={"button": "local_chat"}
108
        )
109
        kb.add_line()
110
        kb.add_button(
111
            label="Назад", payload={"button": "prefs"},
112
        )
113
        return kb.get_keyboard()
114
115
    @staticmethod
116
    def generate_local_chat_prefs(chat):
117
        kb = VkKeyboard()
118
        if chat:
119
            kb.add_button(
120
                label="Переключиться на тестовую беседу",
121
                payload={"button": "activate_test_chat"},
122
            )
123
        else:
124
            kb.add_button(
125
                label="Переключиться на основную беседу",
126
                payload={"button": "activate_main_chat"},
127
            )
128
        kb.add_line()
129
        kb.add_button(label="Назад", payload={"button": "chats"})
130
        return kb.get_keyboard()
131
132
    def generate_global_chat_prefs(self, group: int):
133
        kb = VkKeyboard()
134
        chats = self.db.get_chats_of_group(group)
135
        for i, v in enumerate(chats):
136
            if len(kb.lines[-1]) == 2:
137
                kb.add_line()
138
            if v[1]:
139
                kb.add_button(
140
                    label="Основная беседа",
141
                    payload={
142
                        "button": "configure_chat",
143
                        "group": group,
144
                        "chat_type": 1,
145
                        "chat_id": v[0],
146
                    },
147
                )
148
            else:
149
                kb.add_button(
150
                    label="Тестовая беседа",
151
                    payload={
152
                        "button": "configure_chat",
153
                        "group": group,
154
                        "chat_type": 0,
155
                        "chat_id": v[0],
156
                    },
157
                )
158
        if len(chats) < 2 and self.db.get_cached_chats():
159
            kb.add_button(label="Зарегистрировать чат", payload={"button": "reg_chat"})
160
        kb.add_line()
161
        kb.add_button(label="Назад", payload={"button": "chats"})
162
        return kb.get_keyboard()
163
164
    @staticmethod
165
    def reg_chat(chats, chats_info):
166
        kb = VkKeyboard()
167
        for i, v in enumerate(chats):
168
            try:
169
                label = chats_info["items"][i]["chat_settings"]["title"]
170
            except IndexError:
171
                label = "???"
172
            kb.add_button(
173
                label=label, payload={"button": "add_chat", "chat_id": v},
174
            )
175
            if len(kb.lines[-1]) == 2:
176
                kb.add_line()
177
        if kb.lines[-1]:
178
            kb.add_line()
179
        kb.add_button(label="Назад", payload={"button": "global_chat"})
180
        return kb.get_keyboard()
181
182
    def configure_chat(self, group: int, chat_type: int, chat_id: int):
183
        kb = VkKeyboard()
184
        if not self.db.is_chat_active(group, chat_type):
185
            kb.add_button(
186
                label="Активировать чат",
187
                payload={
188
                    "button": "activate_chat",
189
                    "group": group,
190
                    "chat_type": chat_type,
191
                    "chat_id": chat_id,
192
                },
193
            )
194
        kb.add_button(
195
            label="Открепить чат",
196
            payload={
197
                "button": "unpin_chat",
198
                "group": group,
199
                "chat_type": chat_type,
200
                "chat_id": chat_id,
201
            },
202
        )
203
        if kb.lines[-1]:
204
            kb.add_line()
205
        kb.add_button(label="Назад", payload={"button": "global_chat"})
206
        return kb.get_keyboard()
207
208
    def generate_available_chat_types(self, chat_id: int, group: int):
209
        kb = VkKeyboard()
210
        if not self.db.is_main_chat_added(group):
211
            kb.add_button(
212
                label="Основной", payload={"button": "reg_as_main", "chat_id": chat_id}
213
            )
214
        if not self.db.is_test_chat_added(group):
215
            kb.add_button(
216
                label="Тестовый", payload={"button": "reg_as_test", "chat_id": chat_id}
217
            )
218
        kb.add_line()
219
        kb.add_button(label="Назад", payload={"button": "reg_chat"})
220
        return kb.get_keyboard()
221
222
    @staticmethod
223
    def generate_names_selector(status: bool):
224
        kb = VkKeyboard()
225
        if status:
226
            kb.add_button(label="Выключить", payload={"button": "off_using_names"})
227
        else:
228
            kb.add_button(label="Включить", payload={"button": "on_using_names"})
229
        kb.add_line()
230
        kb.add_button(
231
            label="Назад", payload={"button": "prefs"},
232
        )
233
        return kb.get_keyboard()
234
235
    @staticmethod
236
    def fin_category_menu():
237
        kb = VkKeyboard()
238
        kb.add_button(label="📈 Доход", payload={"button": "add_donate"})
239
        kb.add_button(label="📉 Расход", payload={"button": "add_expense"})
240
        kb.add_line()
241
        kb.add_button(label="Статистика", payload={"button": "fin_stat"})
242
        kb.add_line()
243
        kb.add_button(label="📢 Должники", payload={"button": "debtors"})
244
        kb.add_button(label="⚙ Настройки", payload={"button": "fin_prefs"})
245
        kb.add_line()
246
        kb.add_button(label="👈🏻 Назад", payload={"button": "finances"})
247
        return kb.get_keyboard()
248
249
    @staticmethod
250
    def fin_prefs():
251
        kb = VkKeyboard()
252
        kb.add_button(label="Изменить сумму", payload={"button": "update_summ"})
253
        kb.add_button(label="Переименовать", payload={"button": "update_name"})
254
        kb.add_line()
255
        kb.add_button(label="Удалить", payload={"button": "delete_expense"})
256
        kb.add_line()
257
        kb.add_button(
258
            label="Назад", payload={"button": "fin_category"},
259
        )
260
        return kb.get_keyboard()
261
262
    @staticmethod
263
    def inline_unsubscribe(m_id, sub_id):
264
        kb = VkKeyboard(inline=True)
265
        kb.add_button(
266
            label="Отписаться от таких сообщений",
267
            payload={"button": "inline_unsubscribe", "slug": m_id, "user_id": sub_id},
268
        )
269
        return kb.get_keyboard()
270
271
    def generate_call_prompt(self, group: int):
272
        kb = self.generate_alphabet_keyboard(group)
273
        kb.add_line()
274
        kb.add_button(label="Отмена", payload={"button": "cancel"})
275
        kb.add_button(label="Сохранить", payload={"button": "save"})
276
        kb.add_line()
277
        kb.add_button(label="Отправить всем", payload={"button": "send_to_all"})
278
        return kb.get_keyboard()
279
280
    def generate_finances_prompt(self, group):
281
        kb = self.generate_alphabet_keyboard(group)
282
        kb.add_line()
283
        kb.add_button(label="Отмена", payload={"button": "cancel"})
284
        return kb.get_keyboard()
285
286
    def generate_alphabet_keyboard(self, group: int):
287
        """
288
        Генерирует клавиатуру с алфавитными кнопками
289
        """
290
        kb = VkKeyboard()
291
        letters = self.db.get_last_names_letters(group)
292
        for i, v in enumerate(letters):
293
            if len(kb.lines[-1]) < 4:
294
                kb.add_button(label=v, payload={"button": "letter", "letter": v})
295
            else:
296
                kb.add_line()
297
                kb.add_button(label=v, payload={"button": "letter", "letter": v})
298
299
        return kb
300
301
    def generate_names_keyboard(self, letter: str, group: int):
302
        """
303
        Генерирует клавиатуру с фамилиями, начинающимися на букву (аргумент)
304
        """
305
        names = self.db.get_list_of_names(letter=letter, group=group)
306
        kb = VkKeyboard()
307
        for i, v in enumerate(names):
308
            label = f"{v[2]} {v[1][0]}."
309
            kb.add_button(
310
                label=label, payload={"button": "student", "name": label, "id": v[0]},
311
            )
312
            if len(kb.lines[-1]) == 2:
313
                kb.add_line()
314
        if kb.lines[-1]:
315
            kb.add_line()
316
        kb.add_button(
317
            label="Назад", payload={"button": "back"},
318
        )
319
        return kb.get_keyboard()
320
321
    def generate_mailings_keyboard(self, group: int):
322
        """
323
        Генерация клавиатуры со списком доступных рассылок
324
        """
325
        mailings = self.db.get_mailings_list(group)
326
        kb = VkKeyboard()
327
        for i, v in enumerate(mailings):
328
            kb.add_button(
329
                label=v[1], payload={"button": "mailing", "name": v[1], "id": v[0]},
330
            )
331
            if len(kb.lines[-1]) == 2:
332
                kb.add_line()
333
        if kb.lines[-1]:
334
            kb.add_line()
335
        kb.add_button(
336
            label="Назад", payload={"button": "home"},
337
        )
338
        return kb.get_keyboard()
339
340
    def generate_mailing_mgmt(self, user_id: int, is_admin: bool, m_id: int):
341
        uid = self.db.get_user_id(vk_id=user_id)
342
        status = self.db.get_subscription_status(m_id=m_id, user_id=uid)
343
344
        kb = VkKeyboard()
345
        if is_admin:
346
            kb.add_button(
347
                label="Отправить рассылку",
348
                payload={"button": "send_mailing", "mailing": m_id},
349
            )
350
        kb.add_button(
351
            label=f"{'Отписаться' if status else 'Подписаться'}",
352
            payload={
353
                "button": f"{'unsubscribe' if status else 'subscribe'}",
354
                "slug": m_id,
355
                "user_id": uid,
356
            },
357
        )
358
        kb.add_line()
359
        kb.add_button(
360
            label="Назад", payload={"button": "mailings"},
361
        )
362
        return kb.get_keyboard()
363
364
    def prompt(self, user_id: int = None):
365
        """
366
        Возвращает клавиатуру с подтверждением действия
367
        """
368
        kb = VkKeyboard()
369
        kb.add_button(label="Подтвердить", payload={"button": "confirm"})
370
        kb.add_button(label="Отмена", payload={"button": "deny"})
371
        if user_id is not None and self.db.get_session_state(user_id) in [
372
            "call_configuring",
373
            "debtors_forming",
374
        ]:
375
            kb.add_line()
376
            kb.add_button(
377
                label="Сменить беседу", payload={"button": "chconv_call"},
378
            )
379
            kb.add_line()
380
            kb.add_button(
381
                label="Переключить использование имён",
382
                payload={"button": "chnames_call"},
383
            )
384
        return kb.get_keyboard()
385
386
    def finances_main(self, group: int):
387
        kb = VkKeyboard()
388
        list_of_cats = self.db.get_list_of_finances_categories(group)
389
        for i, v in enumerate(list_of_cats):
390
            label = v[1]
391
            kb.add_button(
392
                label=label,
393
                payload={"button": "fin_category", "id": v[0], "name": v[1]},
394
            )
395
            if len(kb.lines[-1]) == 2:
396
                kb.add_line()
397
        if kb.lines[-1]:
398
            kb.add_line()
399
        kb.add_button(label="Баланс", payload={"button": "balance"})
400
        kb.add_button(label="Добавить статью", payload={"button": "add_expense_cat"})
401
        kb.add_line()
402
        kb.add_button(label="Назад", payload={"button": "home"})
403
        return kb.get_keyboard()
404
405
    def generate_administrating_groups(self, admin_id):
406
        kb = VkKeyboard()
407
        groups = self.db.get_administrating_groups(admin_id)
408
        for i, v in enumerate(groups):
409
            label = v
410
            kb.add_button(
411
                label=label, payload={"button": "get_auth_link", "group": v},
412
            )
413
            if len(kb.lines[-1]) == 2:
414
                kb.add_line()
415
        if kb.lines[-1]:
416
            kb.add_line()
417
        kb.add_button(label="Назад", payload={"button": "home"})
418
        return kb.get_keyboard()
419