some
This commit is contained in:
parent
f48cc365e1
commit
3728863b63
23
package.json
23
package.json
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "telegram-invite-automation",
|
"name": "telegram-invite-automation",
|
||||||
"version": "1.2.0",
|
"version": "1.3.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"description": "Automated user parsing and invites for Telegram groups",
|
"description": "Automated user parsing and invites for Telegram groups",
|
||||||
"main": "src/main/index.js",
|
"main": "src/main/index.js",
|
||||||
@ -8,16 +8,16 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "concurrently -k \"vite\" \"wait-on http://127.0.0.1:5173 && electron .\"",
|
"dev": "concurrently -k \"vite\" \"wait-on http://127.0.0.1:5173 && electron .\"",
|
||||||
"start": "electron .",
|
"start": "electron .",
|
||||||
"build": "vite build && electron-builder",
|
"build": "NODE_OPTIONS=--no-warnings vite build && NODE_OPTIONS=--no-warnings electron-builder",
|
||||||
"build:win": "vite build && electron-builder --win",
|
"build:win": "NODE_OPTIONS=--no-warnings vite build && NODE_OPTIONS=--no-warnings electron-builder --win",
|
||||||
"build:win:x64": "vite build && electron-builder --win --x64",
|
"build:win:x64": "NODE_OPTIONS=--no-warnings vite build && NODE_OPTIONS=--no-warnings electron-builder --win --x64",
|
||||||
"build:win:x64:installer": "vite build && electron-builder --win --x64 --config.win.target=nsis",
|
"build:win:x64:installer": "NODE_OPTIONS=--no-warnings vite build && NODE_OPTIONS=--no-warnings electron-builder --win --x64 --config.win.target=nsis",
|
||||||
"build:win:x64:portable": "vite build && electron-builder --win --x64 --config.win.target=portable",
|
"build:win:x64:portable": "NODE_OPTIONS=--no-warnings vite build && NODE_OPTIONS=--no-warnings electron-builder --win --x64 --config.win.target=portable",
|
||||||
"build:win:x64:portable:zip": "npm run build:win:x64:portable && zip -j -o dist/release/Telegram-Invite-Automation-win-portable-x64.zip dist/release/Telegram-Invite-Automation-win-x64-*.exe",
|
"build:win:x64:portable:zip": "npm run build:win:x64:portable && zip -j -o dist/release/Telegram-Invite-Automation-win-portable-x64.zip dist/release/Telegram-Invite-Automation-win-x64-*.exe",
|
||||||
"build:mac": "vite build && electron-builder --mac",
|
"build:mac": "NODE_OPTIONS=--no-warnings vite build && NODE_OPTIONS=--no-warnings electron-builder --mac",
|
||||||
"build:all": "vite build && electron-builder --win --mac",
|
"build:all": "NODE_OPTIONS=--no-warnings vite build && NODE_OPTIONS=--no-warnings electron-builder --win --mac",
|
||||||
"build:linux": "vite build && electron-builder --linux",
|
"build:linux": "NODE_OPTIONS=--no-warnings vite build && NODE_OPTIONS=--no-warnings electron-builder --linux",
|
||||||
"dist": "vite build && electron-builder",
|
"dist": "NODE_OPTIONS=--no-warnings vite build && NODE_OPTIONS=--no-warnings electron-builder",
|
||||||
"build:converter:mac": "bash scripts/build-converter.sh",
|
"build:converter:mac": "bash scripts/build-converter.sh",
|
||||||
"build:converter:win": "powershell -ExecutionPolicy Bypass -File scripts/build-converter.ps1"
|
"build:converter:win": "powershell -ExecutionPolicy Bypass -File scripts/build-converter.ps1"
|
||||||
},
|
},
|
||||||
@ -29,6 +29,7 @@
|
|||||||
"react-dom": "^18.2.0"
|
"react-dom": "^18.2.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@electron/notarize": "^2.2.0",
|
||||||
"@vitejs/plugin-react": "^4.2.1",
|
"@vitejs/plugin-react": "^4.2.1",
|
||||||
"concurrently": "^8.2.2",
|
"concurrently": "^8.2.2",
|
||||||
"electron": "^29.1.0",
|
"electron": "^29.1.0",
|
||||||
@ -69,12 +70,14 @@
|
|||||||
"asarUnpack": [
|
"asarUnpack": [
|
||||||
"**/*.node"
|
"**/*.node"
|
||||||
],
|
],
|
||||||
|
"afterSign": "scripts/notarize.js",
|
||||||
"electronLanguages": [
|
"electronLanguages": [
|
||||||
"ru",
|
"ru",
|
||||||
"en-US"
|
"en-US"
|
||||||
],
|
],
|
||||||
"mac": {
|
"mac": {
|
||||||
"category": "public.app-category.productivity",
|
"category": "public.app-category.productivity",
|
||||||
|
"hardenedRuntime": true,
|
||||||
"target": [
|
"target": [
|
||||||
"dmg"
|
"dmg"
|
||||||
],
|
],
|
||||||
|
|||||||
28
scripts/notarize.js
Normal file
28
scripts/notarize.js
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
const path = require("path");
|
||||||
|
const { notarize } = require("@electron/notarize");
|
||||||
|
|
||||||
|
exports.default = async function notarizing(context) {
|
||||||
|
const { electronPlatformName, appOutDir } = context;
|
||||||
|
if (electronPlatformName !== "darwin") return;
|
||||||
|
|
||||||
|
const appleId = process.env.APPLE_ID;
|
||||||
|
const appleIdPassword = process.env.APPLE_ID_PASSWORD;
|
||||||
|
const teamId = process.env.APPLE_TEAM_ID;
|
||||||
|
|
||||||
|
if (!appleId || !appleIdPassword || !teamId) {
|
||||||
|
console.log("[notarize] Skipped: APPLE_ID / APPLE_ID_PASSWORD / APPLE_TEAM_ID not set.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const appName = context.packager.appInfo.productFilename;
|
||||||
|
const appPath = path.join(appOutDir, `${appName}.app`);
|
||||||
|
|
||||||
|
console.log(`[notarize] Notarizing ${appPath}`);
|
||||||
|
await notarize({
|
||||||
|
tool: "notarytool",
|
||||||
|
appPath,
|
||||||
|
appleId,
|
||||||
|
appleIdPassword,
|
||||||
|
teamId
|
||||||
|
});
|
||||||
|
};
|
||||||
@ -235,8 +235,10 @@ export default function App() {
|
|||||||
pushStep("Проверка прав инвайта", okCount > 0 ? "ok" : "warn", `OK: ${okCount} / ${inviteAccessStatus.length}`);
|
pushStep("Проверка прав инвайта", okCount > 0 ? "ok" : "warn", `OK: ${okCount} / ${inviteAccessStatus.length}`);
|
||||||
}
|
}
|
||||||
pushStep("Очередь", queueStats.total > 0 ? "ok" : "warn", `В очереди: ${queueStats.total}`);
|
pushStep("Очередь", queueStats.total > 0 ? "ok" : "warn", `В очереди: ${queueStats.total}`);
|
||||||
const intervalOk = Number(taskForm.minInterval) <= Number(taskForm.maxInterval);
|
const minInterval = Number(taskForm.minIntervalMinutes || 0);
|
||||||
pushStep("Интервалы и лимиты", intervalOk ? "ok" : "warn", `Мин: ${taskForm.minInterval} · Макс: ${taskForm.maxInterval}`);
|
const maxInterval = Number(taskForm.maxIntervalMinutes || 0);
|
||||||
|
const intervalOk = minInterval > 0 && maxInterval > 0 && minInterval <= maxInterval;
|
||||||
|
pushStep("Интервалы и лимиты", intervalOk ? "ok" : "warn", `Мин: ${minInterval || "—"} · Макс: ${maxInterval || "—"}`);
|
||||||
if (taskForm.inviteViaAdmins) {
|
if (taskForm.inviteViaAdmins) {
|
||||||
pushStep("Инвайт через админов", taskForm.inviteAdminMasterId ? "ok" : "warn", taskForm.inviteAdminMasterId ? "Мастер-админ выбран" : "Не выбран мастер-админ");
|
pushStep("Инвайт через админов", taskForm.inviteAdminMasterId ? "ok" : "warn", taskForm.inviteAdminMasterId ? "Мастер-админ выбран" : "Не выбран мастер-админ");
|
||||||
} else {
|
} else {
|
||||||
@ -552,7 +554,9 @@ export default function App() {
|
|||||||
loadAccountAssignments,
|
loadAccountAssignments,
|
||||||
showNotification,
|
showNotification,
|
||||||
setTaskNotice,
|
setTaskNotice,
|
||||||
setAccounts
|
setAccounts,
|
||||||
|
membershipStatus,
|
||||||
|
refreshMembership
|
||||||
});
|
});
|
||||||
const { applyTaskPreset } = useTaskPresets({
|
const { applyTaskPreset } = useTaskPresets({
|
||||||
hasSelectedTask,
|
hasSelectedTask,
|
||||||
@ -883,8 +887,6 @@ export default function App() {
|
|||||||
accessStatus,
|
accessStatus,
|
||||||
roleSummary,
|
roleSummary,
|
||||||
mutualContactDiagnostics,
|
mutualContactDiagnostics,
|
||||||
accountById,
|
|
||||||
formatAccountLabel,
|
|
||||||
accountEvents,
|
accountEvents,
|
||||||
clearAccountEvents,
|
clearAccountEvents,
|
||||||
onSettingsChange,
|
onSettingsChange,
|
||||||
|
|||||||
@ -11,7 +11,9 @@ export default function useAccountManagement({
|
|||||||
loadAccountAssignments,
|
loadAccountAssignments,
|
||||||
showNotification,
|
showNotification,
|
||||||
setTaskNotice,
|
setTaskNotice,
|
||||||
setAccounts
|
setAccounts,
|
||||||
|
membershipStatus,
|
||||||
|
refreshMembership
|
||||||
}) {
|
}) {
|
||||||
const persistAccountRoles = async (next) => {
|
const persistAccountRoles = async (next) => {
|
||||||
if (!window.api || selectedTaskId == null) return;
|
if (!window.api || selectedTaskId == null) return;
|
||||||
@ -76,7 +78,7 @@ export default function useAccountManagement({
|
|||||||
persistAccountRoles(next);
|
persistAccountRoles(next);
|
||||||
};
|
};
|
||||||
|
|
||||||
const applyRolePreset = (type) => {
|
const applyRolePreset = async (type) => {
|
||||||
if (!hasSelectedTask) return;
|
if (!hasSelectedTask) return;
|
||||||
const availableIds = selectedAccountIds.length
|
const availableIds = selectedAccountIds.length
|
||||||
? selectedAccountIds
|
? selectedAccountIds
|
||||||
@ -116,11 +118,62 @@ export default function useAccountManagement({
|
|||||||
const existing = taskAccountRoles[id] || {};
|
const existing = taskAccountRoles[id] || {};
|
||||||
next[id] = { monitor: false, invite: false, confirm: true, inviteLimit: existing.inviteLimit || 0 };
|
next[id] = { monitor: false, invite: false, confirm: true, inviteLimit: existing.inviteLimit || 0 };
|
||||||
});
|
});
|
||||||
|
if (monitorIds.length < monitorCount) {
|
||||||
|
if (typeof refreshMembership === "function") {
|
||||||
|
await refreshMembership("roles");
|
||||||
|
}
|
||||||
|
const monitorRoleIds = Object.entries(next)
|
||||||
|
.filter(([, roles]) => roles && roles.monitor)
|
||||||
|
.map(([id]) => Number(id));
|
||||||
|
const monitorInCompetitors = monitorRoleIds.filter((id) => {
|
||||||
|
const membership = membershipStatus && membershipStatus[id];
|
||||||
|
if (!membership) return false;
|
||||||
|
const total = Number(membership.competitorTotal || 0);
|
||||||
|
return total > 0 && Number(membership.competitorCount || 0) > 0;
|
||||||
|
});
|
||||||
|
if (!monitorRoleIds.length) {
|
||||||
|
showNotification("Нет бота мониторинга. Назначьте роль мониторинга.", "error");
|
||||||
|
} else if (!monitorInCompetitors.length) {
|
||||||
|
showNotification("Нет бота мониторинга в группах конкурентов. Введите бота в конкурентов или включите авто‑вступление.", "error");
|
||||||
|
} else {
|
||||||
|
showNotification("Не хватает аккаунтов для роли мониторинга.", "error");
|
||||||
|
}
|
||||||
|
}
|
||||||
if (inviteIds.length < inviteCount) {
|
if (inviteIds.length < inviteCount) {
|
||||||
showNotification("Не хватает аккаунтов для роли инвайта.", "error");
|
if (typeof refreshMembership === "function") {
|
||||||
|
await refreshMembership("roles");
|
||||||
|
}
|
||||||
|
const inviteRoleIds = Object.entries(next)
|
||||||
|
.filter(([, roles]) => roles && roles.invite)
|
||||||
|
.map(([id]) => Number(id));
|
||||||
|
const inviteInOurGroup = inviteRoleIds.filter(
|
||||||
|
(id) => membershipStatus && membershipStatus[id] && membershipStatus[id].ourGroupMember
|
||||||
|
);
|
||||||
|
if (!inviteRoleIds.length) {
|
||||||
|
showNotification("Нет инвайт‑бота. Назначьте роль инвайта.", "error");
|
||||||
|
} else if (!inviteInOurGroup.length) {
|
||||||
|
showNotification("Нет инвайт‑бота в нашей группе. Введите бота в нашу группу или включите авто‑вступление.", "error");
|
||||||
|
} else {
|
||||||
|
showNotification("Не хватает аккаунтов для роли инвайта.", "error");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (taskForm.separateConfirmRoles && confirmIds.length < confirmCount) {
|
if (taskForm.separateConfirmRoles && confirmIds.length < confirmCount) {
|
||||||
showNotification("Не хватает аккаунтов для роли подтверждения.", "error");
|
if (typeof refreshMembership === "function") {
|
||||||
|
await refreshMembership("roles");
|
||||||
|
}
|
||||||
|
const confirmRoleIds = Object.entries(next)
|
||||||
|
.filter(([, roles]) => roles && roles.confirm)
|
||||||
|
.map(([id]) => Number(id));
|
||||||
|
const confirmInOurGroup = confirmRoleIds.filter(
|
||||||
|
(id) => membershipStatus && membershipStatus[id] && membershipStatus[id].ourGroupMember
|
||||||
|
);
|
||||||
|
if (!confirmRoleIds.length) {
|
||||||
|
showNotification("Нет подтверждающего бота. Назначьте роль подтверждения.", "error");
|
||||||
|
} else if (!confirmInOurGroup.length) {
|
||||||
|
showNotification("Нет подтверждающего бота в нашей группе. Введите бота в нашу группу или включите авто‑вступление.", "error");
|
||||||
|
} else {
|
||||||
|
showNotification("Не хватает аккаунтов для роли подтверждения.", "error");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const ids = Object.keys(next).map((id) => Number(id));
|
const ids = Object.keys(next).map((id) => Number(id));
|
||||||
|
|||||||
@ -108,8 +108,6 @@ export default function useAppTabGroups({
|
|||||||
accessStatus,
|
accessStatus,
|
||||||
roleSummary,
|
roleSummary,
|
||||||
mutualContactDiagnostics,
|
mutualContactDiagnostics,
|
||||||
accountById,
|
|
||||||
formatAccountLabel,
|
|
||||||
accountEvents,
|
accountEvents,
|
||||||
clearAccountEvents,
|
clearAccountEvents,
|
||||||
onSettingsChange,
|
onSettingsChange,
|
||||||
|
|||||||
@ -99,14 +99,6 @@ export default function useTabProps(
|
|||||||
setConfirmPage,
|
setConfirmPage,
|
||||||
confirmPageCount,
|
confirmPageCount,
|
||||||
pagedConfirmQueue,
|
pagedConfirmQueue,
|
||||||
queueItems,
|
|
||||||
queueStats,
|
|
||||||
queueSearch,
|
|
||||||
setQueueSearch,
|
|
||||||
queuePage,
|
|
||||||
setQueuePage,
|
|
||||||
queuePageCount,
|
|
||||||
pagedQueue,
|
|
||||||
clearConfirmQueue,
|
clearConfirmQueue,
|
||||||
auditSearch,
|
auditSearch,
|
||||||
setAuditSearch,
|
setAuditSearch,
|
||||||
@ -122,9 +114,7 @@ export default function useTabProps(
|
|||||||
selectedTask,
|
selectedTask,
|
||||||
accessStatus,
|
accessStatus,
|
||||||
roleSummary,
|
roleSummary,
|
||||||
mutualContactDiagnostics,
|
mutualContactDiagnostics
|
||||||
accountById,
|
|
||||||
formatAccountLabel
|
|
||||||
} = logsTab;
|
} = logsTab;
|
||||||
const {
|
const {
|
||||||
queueStats,
|
queueStats,
|
||||||
@ -242,14 +232,6 @@ export default function useTabProps(
|
|||||||
setConfirmPage,
|
setConfirmPage,
|
||||||
confirmPageCount,
|
confirmPageCount,
|
||||||
pagedConfirmQueue,
|
pagedConfirmQueue,
|
||||||
queueItems,
|
|
||||||
queueStats,
|
|
||||||
queueSearch,
|
|
||||||
setQueueSearch,
|
|
||||||
queuePage,
|
|
||||||
setQueuePage,
|
|
||||||
queuePageCount,
|
|
||||||
pagedQueue,
|
|
||||||
clearConfirmQueue,
|
clearConfirmQueue,
|
||||||
auditSearch,
|
auditSearch,
|
||||||
setAuditSearch,
|
setAuditSearch,
|
||||||
|
|||||||
@ -1962,6 +1962,38 @@ label .hint {
|
|||||||
margin-top: 6px;
|
margin-top: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.log-table {
|
||||||
|
display: grid;
|
||||||
|
gap: 8px;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.log-head,
|
||||||
|
.log-row {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1.2fr 1.6fr 1.4fr 0.6fr 0.8fr;
|
||||||
|
gap: 12px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.log-head {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #64748b;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.log-row {
|
||||||
|
padding: 8px 0;
|
||||||
|
border-bottom: 1px solid #e2e8f0;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.log-empty {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #64748b;
|
||||||
|
padding: 8px 0;
|
||||||
|
}
|
||||||
|
|
||||||
.log-result {
|
.log-result {
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
color: #1f2937;
|
color: #1f2937;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user