hh-applicant-tool 0.6.0__tar.gz → 0.6.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of hh-applicant-tool might be problematic. Click here for more details.
- {hh_applicant_tool-0.6.0 → hh_applicant_tool-0.6.2}/PKG-INFO +5 -1
- {hh_applicant_tool-0.6.0 → hh_applicant_tool-0.6.2}/README.md +4 -0
- {hh_applicant_tool-0.6.0 → hh_applicant_tool-0.6.2}/hh_applicant_tool/main.py +3 -0
- {hh_applicant_tool-0.6.0 → hh_applicant_tool-0.6.2}/hh_applicant_tool/operations/apply_similar.py +7 -22
- {hh_applicant_tool-0.6.0 → hh_applicant_tool-0.6.2}/hh_applicant_tool/operations/call_api.py +1 -1
- {hh_applicant_tool-0.6.0 → hh_applicant_tool-0.6.2}/hh_applicant_tool/operations/get_employer_contacts.py +105 -106
- {hh_applicant_tool-0.6.0 → hh_applicant_tool-0.6.2}/hh_applicant_tool/operations/reply_employers.py +91 -15
- {hh_applicant_tool-0.6.0 → hh_applicant_tool-0.6.2}/hh_applicant_tool/telemetry_client.py +1 -1
- {hh_applicant_tool-0.6.0 → hh_applicant_tool-0.6.2}/pyproject.toml +1 -1
- {hh_applicant_tool-0.6.0 → hh_applicant_tool-0.6.2}/hh_applicant_tool/__init__.py +0 -0
- {hh_applicant_tool-0.6.0 → hh_applicant_tool-0.6.2}/hh_applicant_tool/__main__.py +0 -0
- {hh_applicant_tool-0.6.0 → hh_applicant_tool-0.6.2}/hh_applicant_tool/ai/__init__.py +0 -0
- {hh_applicant_tool-0.6.0 → hh_applicant_tool-0.6.2}/hh_applicant_tool/ai/blackbox.py +0 -0
- {hh_applicant_tool-0.6.0 → hh_applicant_tool-0.6.2}/hh_applicant_tool/api/__init__.py +0 -0
- {hh_applicant_tool-0.6.0 → hh_applicant_tool-0.6.2}/hh_applicant_tool/api/client.py +0 -0
- {hh_applicant_tool-0.6.0 → hh_applicant_tool-0.6.2}/hh_applicant_tool/api/errors.py +0 -0
- {hh_applicant_tool-0.6.0 → hh_applicant_tool-0.6.2}/hh_applicant_tool/color_log.py +0 -0
- {hh_applicant_tool-0.6.0 → hh_applicant_tool-0.6.2}/hh_applicant_tool/constants.py +0 -0
- {hh_applicant_tool-0.6.0 → hh_applicant_tool-0.6.2}/hh_applicant_tool/jsonc.py +0 -0
- {hh_applicant_tool-0.6.0 → hh_applicant_tool-0.6.2}/hh_applicant_tool/mixins.py +0 -0
- {hh_applicant_tool-0.6.0 → hh_applicant_tool-0.6.2}/hh_applicant_tool/operations/__init__.py +0 -0
- {hh_applicant_tool-0.6.0 → hh_applicant_tool-0.6.2}/hh_applicant_tool/operations/authorize.py +0 -0
- {hh_applicant_tool-0.6.0 → hh_applicant_tool-0.6.2}/hh_applicant_tool/operations/clear_negotiations.py +0 -0
- {hh_applicant_tool-0.6.0 → hh_applicant_tool-0.6.2}/hh_applicant_tool/operations/config.py +0 -0
- {hh_applicant_tool-0.6.0 → hh_applicant_tool-0.6.2}/hh_applicant_tool/operations/delete_telemetry.py +0 -0
- {hh_applicant_tool-0.6.0 → hh_applicant_tool-0.6.2}/hh_applicant_tool/operations/list_resumes.py +0 -0
- {hh_applicant_tool-0.6.0 → hh_applicant_tool-0.6.2}/hh_applicant_tool/operations/refresh_token.py +0 -0
- {hh_applicant_tool-0.6.0 → hh_applicant_tool-0.6.2}/hh_applicant_tool/operations/update_resumes.py +0 -0
- {hh_applicant_tool-0.6.0 → hh_applicant_tool-0.6.2}/hh_applicant_tool/operations/whoami.py +0 -0
- {hh_applicant_tool-0.6.0 → hh_applicant_tool-0.6.2}/hh_applicant_tool/types.py +0 -0
- {hh_applicant_tool-0.6.0 → hh_applicant_tool-0.6.2}/hh_applicant_tool/utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: hh-applicant-tool
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.2
|
|
4
4
|
Summary:
|
|
5
5
|
Author: Senior YAML Developer
|
|
6
6
|
Author-email: yamldeveloper@proton.me
|
|
@@ -209,6 +209,10 @@ $ hh-applicant-tool update-resumes
|
|
|
209
209
|
|
|
210
210
|
# Чистим заявки и баним за отказы говноконторы
|
|
211
211
|
$ hh-applicant-tool clear-negotiations --blacklist-discard
|
|
212
|
+
|
|
213
|
+
# Экспортировать в HTML, контакты работодателей, которые когда-либо высылали вам
|
|
214
|
+
# приглашение
|
|
215
|
+
$ hh-applicant-tool get-employer-contacts --export -f html > report.html
|
|
212
216
|
```
|
|
213
217
|
|
|
214
218
|
Можно вызвать любой метод API:
|
|
@@ -190,6 +190,10 @@ $ hh-applicant-tool update-resumes
|
|
|
190
190
|
|
|
191
191
|
# Чистим заявки и баним за отказы говноконторы
|
|
192
192
|
$ hh-applicant-tool clear-negotiations --blacklist-discard
|
|
193
|
+
|
|
194
|
+
# Экспортировать в HTML, контакты работодателей, которые когда-либо высылали вам
|
|
195
|
+
# приглашение
|
|
196
|
+
$ hh-applicant-tool get-employer-contacts --export -f html > report.html
|
|
193
197
|
```
|
|
194
198
|
|
|
195
199
|
Можно вызвать любой метод API:
|
|
@@ -150,6 +150,9 @@ class HHApplicantTool:
|
|
|
150
150
|
if (token := api_client.get_access_token()) != args.config["token"]:
|
|
151
151
|
args.config.save(token=token)
|
|
152
152
|
return res
|
|
153
|
+
except KeyboardInterrupt:
|
|
154
|
+
logger.warning("Interrupted by user")
|
|
155
|
+
return 1
|
|
153
156
|
except Exception as e:
|
|
154
157
|
logger.exception(e)
|
|
155
158
|
return 1
|
{hh_applicant_tool-0.6.0 → hh_applicant_tool-0.6.2}/hh_applicant_tool/operations/apply_similar.py
RENAMED
|
@@ -255,28 +255,13 @@ class Operation(BaseOperation, GetResumeIdMixin):
|
|
|
255
255
|
"area": employer.get("area", {}).get("name"), # город
|
|
256
256
|
}
|
|
257
257
|
if "got_rejection" in relations:
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
employer_data,
|
|
266
|
-
)
|
|
267
|
-
if "topic_url" in response:
|
|
268
|
-
print(
|
|
269
|
-
"Ссылка на обсуждение работодателя:",
|
|
270
|
-
response["topic_url"],
|
|
271
|
-
)
|
|
272
|
-
else:
|
|
273
|
-
# print(
|
|
274
|
-
# "Создание темы для обсуждения работодателя добавлено в очередь..."
|
|
275
|
-
# )
|
|
276
|
-
...
|
|
277
|
-
complained_employers.add(employer_id)
|
|
278
|
-
except TelemetryError as ex:
|
|
279
|
-
logger.error(ex)
|
|
258
|
+
print(
|
|
259
|
+
"🚨 Вы получили отказ от https://hh.ru/employer/%s"
|
|
260
|
+
% employer_id
|
|
261
|
+
)
|
|
262
|
+
|
|
263
|
+
complained_employers.add(employer_id)
|
|
264
|
+
|
|
280
265
|
elif do_apply:
|
|
281
266
|
telemetry_data["employers"][employer_id] = employer_data
|
|
282
267
|
|
|
@@ -107,97 +107,97 @@ def generate_html_report(data: list[dict]) -> str:
|
|
|
107
107
|
"""
|
|
108
108
|
Генерирует HTML-отчет на основе предоставленных данных.
|
|
109
109
|
"""
|
|
110
|
-
html_content = """
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
110
|
+
html_content = """\
|
|
111
|
+
<!DOCTYPE html>
|
|
112
|
+
<html lang="ru">
|
|
113
|
+
<head>
|
|
114
|
+
<meta charset="UTF-8">
|
|
115
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
116
|
+
<title>Контакты работодателей</title>
|
|
117
|
+
<style>
|
|
118
|
+
body {
|
|
119
|
+
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
|
120
|
+
margin: 20px;
|
|
121
|
+
background-color: #f4f7f6;
|
|
122
|
+
color: #333;
|
|
123
|
+
}
|
|
124
|
+
.container {
|
|
125
|
+
max-width: 900px;
|
|
126
|
+
margin: 20px auto;
|
|
127
|
+
background-color: #ffffff;
|
|
128
|
+
padding: 30px;
|
|
129
|
+
border-radius: 10px;
|
|
130
|
+
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
|
|
131
|
+
}
|
|
132
|
+
h1 {
|
|
133
|
+
color: #0056b3;
|
|
134
|
+
text-align: center;
|
|
135
|
+
margin-bottom: 30px;
|
|
136
|
+
}
|
|
137
|
+
.person-card {
|
|
138
|
+
background-color: #e9f0f8;
|
|
139
|
+
border: 1px solid #cce5ff;
|
|
140
|
+
border-radius: 8px;
|
|
141
|
+
padding: 20px;
|
|
142
|
+
margin-bottom: 25px;
|
|
143
|
+
transition: transform 0.2s ease-in-out;
|
|
144
|
+
}
|
|
145
|
+
.person-card:hover {
|
|
146
|
+
transform: translateY(-5px);
|
|
147
|
+
}
|
|
148
|
+
.person-card h2 {
|
|
149
|
+
color: #004085;
|
|
150
|
+
margin-top: 0;
|
|
151
|
+
margin-bottom: 10px;
|
|
152
|
+
border-bottom: 2px solid #0056b3;
|
|
153
|
+
padding-bottom: 5px;
|
|
154
|
+
}
|
|
155
|
+
.person-card p {
|
|
156
|
+
margin: 5px 0;
|
|
157
|
+
}
|
|
158
|
+
.person-card strong {
|
|
159
|
+
color: #004085;
|
|
160
|
+
}
|
|
161
|
+
.employer-info {
|
|
162
|
+
background-color: #d1ecf1;
|
|
163
|
+
border-left: 5px solid #007bff;
|
|
164
|
+
padding: 15px;
|
|
165
|
+
margin-top: 15px;
|
|
166
|
+
border-radius: 5px;
|
|
167
|
+
}
|
|
168
|
+
.employer-info h3 {
|
|
169
|
+
color: #0056b3;
|
|
170
|
+
margin-top: 0;
|
|
171
|
+
margin-bottom: 10px;
|
|
172
|
+
}
|
|
173
|
+
ul {
|
|
174
|
+
list-style-type: none;
|
|
175
|
+
padding: 0;
|
|
176
|
+
}
|
|
177
|
+
ul li {
|
|
178
|
+
background-color: #f8fafd;
|
|
179
|
+
padding: 8px 12px;
|
|
180
|
+
margin-bottom: 5px;
|
|
181
|
+
border-radius: 4px;
|
|
182
|
+
border: 1px solid #e0e9f1;
|
|
183
|
+
}
|
|
184
|
+
a {
|
|
185
|
+
color: #007bff;
|
|
186
|
+
text-decoration: none;
|
|
187
|
+
}
|
|
188
|
+
a:hover {
|
|
189
|
+
text-decoration: underline;
|
|
190
|
+
}
|
|
191
|
+
.no-data {
|
|
192
|
+
color: #6c757d;
|
|
193
|
+
font-style: italic;
|
|
194
|
+
}
|
|
195
|
+
</style>
|
|
196
|
+
</head>
|
|
197
|
+
<body>
|
|
198
|
+
<div class="container">
|
|
199
|
+
<h1>Полученные контакты</h1>
|
|
200
|
+
"""
|
|
201
201
|
|
|
202
202
|
for item in data:
|
|
203
203
|
name = item.get("name", "N/A")
|
|
@@ -219,21 +219,21 @@ def generate_html_report(data: list[dict]) -> str:
|
|
|
219
219
|
if "username" in tu
|
|
220
220
|
]
|
|
221
221
|
|
|
222
|
-
html_content += f"""
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
222
|
+
html_content += f"""\
|
|
223
|
+
<div class="person-card">
|
|
224
|
+
<h2>{name}</h2>
|
|
225
|
+
<p><strong>Email:</strong> <a href="mailto:{email}">{email}</a></p>
|
|
226
226
|
"""
|
|
227
227
|
|
|
228
228
|
if employer_name != "N/A":
|
|
229
|
-
html_content += f"""
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
229
|
+
html_content += f"""\
|
|
230
|
+
<div class="employer-info">
|
|
231
|
+
<h3>Работодатель: {employer_name}</h3>
|
|
232
|
+
<p><strong>Город:</strong> {employer_area}</p>
|
|
233
233
|
"""
|
|
234
234
|
if employer_site_url:
|
|
235
|
-
html_content += f"""
|
|
236
|
-
|
|
235
|
+
html_content += f"""\
|
|
236
|
+
<p><strong>Сайт:</strong> <a href="{employer_site_url}" target="_blank">{employer_site_url}</a></p>
|
|
237
237
|
"""
|
|
238
238
|
html_content += "</div>" # Закрываем employer-info
|
|
239
239
|
else:
|
|
@@ -261,11 +261,10 @@ def generate_html_report(data: list[dict]) -> str:
|
|
|
261
261
|
|
|
262
262
|
html_content += "</div>" # Закрываем person-card
|
|
263
263
|
|
|
264
|
-
html_content += """
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
"""
|
|
264
|
+
html_content += """\
|
|
265
|
+
</div>
|
|
266
|
+
</body>
|
|
267
|
+
</html>"""
|
|
269
268
|
return html_content
|
|
270
269
|
|
|
271
270
|
|
{hh_applicant_tool-0.6.0 → hh_applicant_tool-0.6.2}/hh_applicant_tool/operations/reply_employers.py
RENAMED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
import os
|
|
1
3
|
import argparse
|
|
2
4
|
import logging
|
|
3
5
|
import random
|
|
@@ -9,6 +11,22 @@ from ..main import BaseOperation
|
|
|
9
11
|
from ..main import Namespace as BaseNamespace
|
|
10
12
|
from ..mixins import GetResumeIdMixin
|
|
11
13
|
from ..utils import parse_interval, random_text
|
|
14
|
+
from ..telemetry_client import TelemetryClient, TelemetryError
|
|
15
|
+
import re
|
|
16
|
+
|
|
17
|
+
try:
|
|
18
|
+
import readline
|
|
19
|
+
|
|
20
|
+
readline.add_history("/cancel ")
|
|
21
|
+
readline.set_history_length(10_000)
|
|
22
|
+
except ImportError:
|
|
23
|
+
pass
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
GOOGLE_DOCS_RE = re.compile(
|
|
27
|
+
r"\b(?:https?:\/\/)?(?:docs|forms|sheets|slides|drive)\.google\.com\/(?:document|spreadsheets|presentation|forms|file)\/(?:d|u)\/[a-zA-Z0-9_\-]+(?:\/[a-zA-Z0-9_\-]+)?\/?(?:[?#].*)?\b|\b(?:https?:\/\/)?(?:goo\.gl|forms\.gle)\/[a-zA-Z0-9]+\b",
|
|
28
|
+
re.I,
|
|
29
|
+
)
|
|
12
30
|
|
|
13
31
|
logger = logging.getLogger(__package__)
|
|
14
32
|
|
|
@@ -66,8 +84,12 @@ class Operation(BaseOperation, GetResumeIdMixin):
|
|
|
66
84
|
action=argparse.BooleanOptionalAction,
|
|
67
85
|
)
|
|
68
86
|
|
|
69
|
-
def run(
|
|
87
|
+
def run(
|
|
88
|
+
self, args: Namespace, api_client: ApiClient, telemetry_client: TelemetryClient
|
|
89
|
+
) -> None:
|
|
70
90
|
self.api_client = api_client
|
|
91
|
+
self.telemetry_client = telemetry_client
|
|
92
|
+
self.enable_telemetry = not args.disable_telemetry
|
|
71
93
|
self.resume_id = self._get_resume_id()
|
|
72
94
|
self.reply_min_interval, self.reply_max_interval = args.reply_interval
|
|
73
95
|
self.reply_message = args.reply_message or args.config["reply_message"]
|
|
@@ -81,6 +103,8 @@ class Operation(BaseOperation, GetResumeIdMixin):
|
|
|
81
103
|
def _reply_chats(self) -> None:
|
|
82
104
|
me = self.me = self.api_client.get("/me")
|
|
83
105
|
|
|
106
|
+
telemetry_data = {"links": []}
|
|
107
|
+
|
|
84
108
|
basic_message_placeholders = {
|
|
85
109
|
"first_name": me.get("first_name", ""),
|
|
86
110
|
"last_name": me.get("last_name", ""),
|
|
@@ -144,6 +168,32 @@ class Operation(BaseOperation, GetResumeIdMixin):
|
|
|
144
168
|
|
|
145
169
|
page = messages_res["pages"] - 1
|
|
146
170
|
|
|
171
|
+
if self.enable_telemetry:
|
|
172
|
+
# Собираем ссылки на тестовые задания
|
|
173
|
+
for message in message_history:
|
|
174
|
+
if message.startswith("-> "):
|
|
175
|
+
continue
|
|
176
|
+
# Тестовые задания и тп
|
|
177
|
+
for link in GOOGLE_DOCS_RE.findall(message):
|
|
178
|
+
document_data = {
|
|
179
|
+
"vacancy_url": vacancy.get("alternate_url"),
|
|
180
|
+
"vacancy_name": vacancy.get("name"),
|
|
181
|
+
"salary": (
|
|
182
|
+
f"{salary.get('from', '...')}-{salary.get('to', '...')} {salary.get('currency', 'RUR')}" # noqa: E501
|
|
183
|
+
if salary
|
|
184
|
+
else None
|
|
185
|
+
),
|
|
186
|
+
"employer_url": vacancy.get("employer", {}).get(
|
|
187
|
+
"alternate_url"
|
|
188
|
+
),
|
|
189
|
+
"link": link,
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
telemetry_data["links"].append(document_data)
|
|
193
|
+
|
|
194
|
+
if os.getenv("TEST_SEND_TELEMETRY") in ["1", "y", "Y"]:
|
|
195
|
+
continue
|
|
196
|
+
|
|
147
197
|
logger.debug(last_message)
|
|
148
198
|
|
|
149
199
|
is_employer_message = (
|
|
@@ -152,8 +202,10 @@ class Operation(BaseOperation, GetResumeIdMixin):
|
|
|
152
202
|
|
|
153
203
|
if is_employer_message or not negotiation.get("viewed_by_opponent"):
|
|
154
204
|
if self.reply_message:
|
|
155
|
-
|
|
156
|
-
|
|
205
|
+
send_message = (
|
|
206
|
+
random_text(self.reply_message) % message_placeholders
|
|
207
|
+
)
|
|
208
|
+
logger.debug(send_message)
|
|
157
209
|
else:
|
|
158
210
|
print("🏢", message_placeholders["employer_name"])
|
|
159
211
|
print("💼", message_placeholders["vacancy_name"])
|
|
@@ -173,9 +225,17 @@ class Operation(BaseOperation, GetResumeIdMixin):
|
|
|
173
225
|
else message_history
|
|
174
226
|
):
|
|
175
227
|
print(msg)
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
228
|
+
try:
|
|
229
|
+
print("-" * 10)
|
|
230
|
+
print()
|
|
231
|
+
print(
|
|
232
|
+
"Чтобы отменить отклик введите /cancel <необязательное сообщение для отказа>"
|
|
233
|
+
)
|
|
234
|
+
print()
|
|
235
|
+
send_message = input("Ваше сообщение: ").strip()
|
|
236
|
+
except EOFError:
|
|
237
|
+
continue
|
|
238
|
+
if not send_message:
|
|
179
239
|
print("🚶 Пропускаем чат")
|
|
180
240
|
continue
|
|
181
241
|
|
|
@@ -183,7 +243,7 @@ class Operation(BaseOperation, GetResumeIdMixin):
|
|
|
183
243
|
logger.info(
|
|
184
244
|
"Dry Run: Отправка сообщения в чат по вакансии %s: %s",
|
|
185
245
|
vacancy["alternate_url"],
|
|
186
|
-
|
|
246
|
+
send_message,
|
|
187
247
|
)
|
|
188
248
|
continue
|
|
189
249
|
|
|
@@ -193,17 +253,33 @@ class Operation(BaseOperation, GetResumeIdMixin):
|
|
|
193
253
|
self.reply_max_interval,
|
|
194
254
|
)
|
|
195
255
|
)
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
256
|
+
|
|
257
|
+
if send_message.startswith("/cancel"):
|
|
258
|
+
_, decline_allowed = send_message.split("/cancel", 1)
|
|
259
|
+
self.api_client.delete(
|
|
260
|
+
f"/negotiations/active/{negotiation['id']}",
|
|
261
|
+
with_decline_message=decline_allowed.strip(),
|
|
262
|
+
)
|
|
263
|
+
print("Отменили заявку", vacancy["alternate_url"])
|
|
264
|
+
else:
|
|
265
|
+
self.api_client.post(
|
|
266
|
+
f"/negotiations/{nid}/messages",
|
|
267
|
+
message=send_message,
|
|
268
|
+
)
|
|
269
|
+
print(
|
|
270
|
+
"📨 Отправили сообщение для",
|
|
271
|
+
vacancy["alternate_url"],
|
|
272
|
+
)
|
|
204
273
|
except ApiError as ex:
|
|
205
274
|
logger.error(ex)
|
|
206
275
|
|
|
276
|
+
if self.enable_telemetry and len(telemetry_data["links"]) > 0:
|
|
277
|
+
logger.debug(telemetry_data)
|
|
278
|
+
try:
|
|
279
|
+
self.telemetry_client.send_telemetry("/docs", telemetry_data)
|
|
280
|
+
except TelemetryError as ex:
|
|
281
|
+
logger.warning(ex, exc_info=True)
|
|
282
|
+
|
|
207
283
|
print("📝 Сообщения разосланы!")
|
|
208
284
|
|
|
209
285
|
def _get_negotiations(self) -> list[dict]:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hh_applicant_tool-0.6.0 → hh_applicant_tool-0.6.2}/hh_applicant_tool/operations/__init__.py
RENAMED
|
File without changes
|
{hh_applicant_tool-0.6.0 → hh_applicant_tool-0.6.2}/hh_applicant_tool/operations/authorize.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hh_applicant_tool-0.6.0 → hh_applicant_tool-0.6.2}/hh_applicant_tool/operations/delete_telemetry.py
RENAMED
|
File without changes
|
{hh_applicant_tool-0.6.0 → hh_applicant_tool-0.6.2}/hh_applicant_tool/operations/list_resumes.py
RENAMED
|
File without changes
|
{hh_applicant_tool-0.6.0 → hh_applicant_tool-0.6.2}/hh_applicant_tool/operations/refresh_token.py
RENAMED
|
File without changes
|
{hh_applicant_tool-0.6.0 → hh_applicant_tool-0.6.2}/hh_applicant_tool/operations/update_resumes.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|