setup funcional
This commit is contained in:
commit
499c02b202
|
|
@ -0,0 +1,97 @@
|
||||||
|
# Microw
|
||||||
|
|
||||||
|
**Microw** é um utilitário de linha de comando (CLI) desenvolvido em Python para automatizar a conversão de dados tabulares (como arquivos CSV ou TXT) em arquivos de configuração `.ini` compatíveis com o softphone **MicroSIP** e seus derivados.
|
||||||
|
|
||||||
|
Esta ferramenta é ideal para administradores de sistemas VoIP, suporte técnico e desenvolvedores que precisam realizar o provisionamento em massa de ramais de forma rápida e precisa.
|
||||||
|
|
||||||
|
## Funcionalidades
|
||||||
|
|
||||||
|
* **Mapeamento Flexível:** Define a ordem das colunas do seu arquivo de entrada via linha de comando.
|
||||||
|
* **Templates Customizáveis:** Permite o uso de modelos de conta personalizados para diferentes cenários de rede.
|
||||||
|
* **Padrões de Label:** Gere nomes de exibição (DisplayName) dinâmicos baseados nos dados de entrada.
|
||||||
|
* **Conta Ghost:** Opção para adicionar um perfil "Desconectado" como primeira conta da lista.
|
||||||
|
* **Suporte a Delimitadores:** Funciona com vírgulas, tabs (`\t`), pontos e vírgulas, etc.
|
||||||
|
|
||||||
|
## Como Usar
|
||||||
|
|
||||||
|
### Pré-requisitos
|
||||||
|
|
||||||
|
* Python 3.x instalado.
|
||||||
|
|
||||||
|
### Instalação
|
||||||
|
|
||||||
|
Basta clonar o repositório ou baixar o arquivo `microw.py`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/LucioCarvalhoDev/microw.git
|
||||||
|
cd microw
|
||||||
|
```
|
||||||
|
|
||||||
|
### Execução Básica
|
||||||
|
|
||||||
|
Supondo que você tenha um arquivo `seus_dados.csv` com o formato `ramal,label`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 microw.py --input seus_dados.csv --output accounts.ini
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Referência de Argumentos
|
||||||
|
|
||||||
|
| Argumento | Padrão | Descrição |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `--format` | `"ramal label"` | Ordem das colunas (use `_` para ignorar colunas). |
|
||||||
|
| `--input` | `./input.txt` | Caminho do arquivo de origem. |
|
||||||
|
| `--output` | `./output.ini` | Caminho do arquivo `.ini` gerado. |
|
||||||
|
| `--delimiter` | `,` | Caractere separador de colunas. |
|
||||||
|
| `--label-pattern` | `label` | Template para o nome de exibição (ex: `"ramal - label"`). |
|
||||||
|
| `--add-ghost` | `False` | Adiciona conta de 'Desconectado' no topo. |
|
||||||
|
| `--set-template` | `None` | Caminho para um arquivo de template de conta customizado. |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Exemplos de Uso
|
||||||
|
|
||||||
|
### 1. Formato CSV com Ponto e Vírgula
|
||||||
|
|
||||||
|
Se o seu arquivo segue o padrão `ID;Ramal;Nome;Setor` e você quer ignorar o ID:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 microw.py --delimiter ";" --format "_ ramal label setor"
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Customizando o Nome de Exibição
|
||||||
|
|
||||||
|
Para que no MicroSIP o nome apareça como `Ramal | Nome (Setor)`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 microw.py --format "ramal label setor" --label-pattern "ramal | label (setor)"
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Usando um Template de Conta Específico
|
||||||
|
|
||||||
|
Se você precisa de configurações de transporte (TLS/TCP) ou portas diferentes, crie um arquivo de template e aponte-o:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 microw.py --set-template meu_modelo.txt --input ramais.txt
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Licença e Créditos
|
||||||
|
|
||||||
|
Desenvolvido por **Lúcio Carvalho Almeida**.
|
||||||
|
|
||||||
|
Este projeto é **Software Livre** (Open Source).
|
||||||
|
|
||||||
|
**Contato:** [luciocarvalhodev@gmail.com](mailto:luciocarvalhodev@gmail.com)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Sinta-se à vontade para contribuir com Pull Requests!
|
||||||
|
|
||||||
|
---
|
||||||
|
|
@ -0,0 +1,242 @@
|
||||||
|
import sys
|
||||||
|
from enum import Enum
|
||||||
|
from pathlib import Path
|
||||||
|
import codecs
|
||||||
|
|
||||||
|
MAN = """
|
||||||
|
NOME
|
||||||
|
microw - convert data to MicroSIP accounts
|
||||||
|
|
||||||
|
USO
|
||||||
|
python3 microw.py [OPÇÔES]
|
||||||
|
|
||||||
|
DESCRIÇÂO
|
||||||
|
Utilitário para conversão de dados tabulares (CSV, TXT) em arquivos de
|
||||||
|
configuração (.ini) para o softphone MicroSIP e variantes.
|
||||||
|
|
||||||
|
Feito por Lúcio Carvalho Almeida, Free Software.
|
||||||
|
|
||||||
|
ARGUMENTOS
|
||||||
|
--format <string> Define a ordem das colunas no arquivo de entrada.
|
||||||
|
Use nomes de variáveis (ex: ramal, password) ou
|
||||||
|
'_' para ignorar uma coluna específica.
|
||||||
|
Padrão: "ramal label"
|
||||||
|
Variáveis especiais: 'name', 'label', 'password',
|
||||||
|
'server'
|
||||||
|
|
||||||
|
--input <path> Caminho do arquivo de origem dos dados.
|
||||||
|
Padrão: "./input.txt"
|
||||||
|
|
||||||
|
--output <path> Caminho onde o arquivo .ini será gerado.
|
||||||
|
Padrão: "./output.ini"
|
||||||
|
|
||||||
|
--delimiter <sep> Caractere separador de colunas (aceita '\\t', ' ').
|
||||||
|
Padrão: ","
|
||||||
|
|
||||||
|
--label-pattern <q> Template para customizar o nome de exibição.
|
||||||
|
Substitui nomes de variáveis pelos seus valores.
|
||||||
|
Ex: "ramal - label (setor)"
|
||||||
|
|
||||||
|
--add-ghost Se presente, adiciona uma conta de 'Desconectado'
|
||||||
|
como o primeiro perfil da lista.
|
||||||
|
|
||||||
|
--set-template <t> Fornece o caminho para o arquivo <t> que será
|
||||||
|
usado no lugar de ACCOUNT_TEMPLATE
|
||||||
|
|
||||||
|
--read-encoding <ienc> Define a codificação de leitura
|
||||||
|
|
||||||
|
EXEMPLOS
|
||||||
|
1. Formato padrão com separador de ponto e vírgula:
|
||||||
|
python3 microw.py --delimiter ";"
|
||||||
|
|
||||||
|
2. Ignorando a 1ª coluna e formatando o nome de exibição:
|
||||||
|
python3 microw.py --format "_ ramal label setor" --label-pattern "label [setor]"
|
||||||
|
|
||||||
|
3. Usando um arquivo específico e adicionando conta fantasma:
|
||||||
|
python3 microw.py --input lista_vendas.csv --add-ghost
|
||||||
|
|
||||||
|
CREDITOS
|
||||||
|
Desenvolvido por Lúcio Carvalho Almeida, Open Source.
|
||||||
|
Contato em luciocarvalhodev@gmail.com.
|
||||||
|
"""
|
||||||
|
|
||||||
|
ACCOUNT_TEMPLATE = r'''
|
||||||
|
[Account_]
|
||||||
|
label=$label
|
||||||
|
server=$server
|
||||||
|
proxy=$server
|
||||||
|
domain=$server
|
||||||
|
username=$ramal
|
||||||
|
password=$password
|
||||||
|
authID=$ramal
|
||||||
|
displayName=
|
||||||
|
dialingPrefix=
|
||||||
|
dialPlan=
|
||||||
|
hideCID=0
|
||||||
|
voicemailNumber=
|
||||||
|
transport=udp
|
||||||
|
publicAddr=
|
||||||
|
SRTP=
|
||||||
|
registerRefresh=300
|
||||||
|
keepAlive=15
|
||||||
|
publish=0
|
||||||
|
ICE=0
|
||||||
|
allowRewrite=0
|
||||||
|
disableSessionTimer=0
|
||||||
|
'''
|
||||||
|
|
||||||
|
GHOST_TEMPLATE = r'''
|
||||||
|
[Account_]
|
||||||
|
label=Desconectado
|
||||||
|
server=0.0.0.0
|
||||||
|
proxy=0.0.0.0
|
||||||
|
domain=0.0.0.0
|
||||||
|
username=0000
|
||||||
|
password=1234
|
||||||
|
authID=0000
|
||||||
|
'''
|
||||||
|
|
||||||
|
class SchemaValue(Enum):
|
||||||
|
Argument = 1
|
||||||
|
Bool = 2
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
def __init__(self):
|
||||||
|
self.config = {
|
||||||
|
"format": {
|
||||||
|
"default": "ramal label",
|
||||||
|
"schema": SchemaValue.Argument,
|
||||||
|
"value": None
|
||||||
|
},
|
||||||
|
"input": {
|
||||||
|
"default": "./input.txt",
|
||||||
|
"schema": SchemaValue.Argument,
|
||||||
|
"value": None
|
||||||
|
},
|
||||||
|
"add-ghost": {
|
||||||
|
"default": False,
|
||||||
|
"schema": SchemaValue.Bool,
|
||||||
|
"value": None
|
||||||
|
},
|
||||||
|
"delimiter": {
|
||||||
|
"default": ",",
|
||||||
|
"schema": SchemaValue.Argument,
|
||||||
|
"value": None
|
||||||
|
},
|
||||||
|
"output": {
|
||||||
|
"default": "./output.ini",
|
||||||
|
"schema": SchemaValue.Argument,
|
||||||
|
"value": None
|
||||||
|
},
|
||||||
|
"label-pattern": {
|
||||||
|
"default": "label",
|
||||||
|
"schema": SchemaValue.Argument,
|
||||||
|
"value": None
|
||||||
|
},
|
||||||
|
"help": {
|
||||||
|
"default": None,
|
||||||
|
"schema": SchemaValue.Bool,
|
||||||
|
"value": None
|
||||||
|
},
|
||||||
|
"set-template": {
|
||||||
|
"default": None,
|
||||||
|
"schema": SchemaValue.Argument,
|
||||||
|
"value": None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def _validate_setting(self, setting):
|
||||||
|
if not setting in self.config:
|
||||||
|
raise ValueError(f"'{setting}' is not a valid option.")
|
||||||
|
|
||||||
|
def get(self, setting):
|
||||||
|
self._validate_setting(setting)
|
||||||
|
return self.config[setting]["value"] or self.config[setting]["default"]
|
||||||
|
|
||||||
|
def set(self, setting, value):
|
||||||
|
self._validate_setting(setting)
|
||||||
|
self.config[setting]["value"] = value
|
||||||
|
|
||||||
|
def schema(self, setting):
|
||||||
|
self._validate_setting(setting)
|
||||||
|
return self.config[setting]["schema"]
|
||||||
|
|
||||||
|
config = Config()
|
||||||
|
|
||||||
|
def main():
|
||||||
|
# Faz o parse manual das flags e argumentos
|
||||||
|
args = sys.argv[1:]
|
||||||
|
while len(args):
|
||||||
|
argument = args.pop(0)
|
||||||
|
if argument[:2] == "--":
|
||||||
|
argument = argument[2:]
|
||||||
|
|
||||||
|
if argument == "help":
|
||||||
|
print(MAN)
|
||||||
|
return
|
||||||
|
|
||||||
|
if config.schema(argument) == SchemaValue.Argument:
|
||||||
|
config.set(argument, codecs.decode(args.pop(0), "unicode_escape"))
|
||||||
|
else:
|
||||||
|
config.set(argument, not config.get(argument))
|
||||||
|
|
||||||
|
output_file = Path(config.get("output"))
|
||||||
|
input_file = Path(config.get("input"))
|
||||||
|
input_lines = [line.strip() for line in input_file.open("r", encoding="utf-8").readlines()]
|
||||||
|
|
||||||
|
accounts_settings = []
|
||||||
|
format_vars = config.get("format").split(" ")
|
||||||
|
label_pattern = config.get("label-pattern")
|
||||||
|
|
||||||
|
for line in input_lines:
|
||||||
|
if not line: continue
|
||||||
|
|
||||||
|
data = [field.strip() for field in line.split(config.get("delimiter"))]
|
||||||
|
account_dict = {}
|
||||||
|
|
||||||
|
# Mapeia os dados ignorando o caractere '_'
|
||||||
|
for i in range(min(len(data), len(format_vars))):
|
||||||
|
var_name = format_vars[i]
|
||||||
|
if var_name != "_":
|
||||||
|
account_dict[var_name] = data[i]
|
||||||
|
|
||||||
|
# Customização do $label
|
||||||
|
if label_pattern:
|
||||||
|
pattern_parts = label_pattern.split(" ")
|
||||||
|
|
||||||
|
# Se a parte for uma variável conhecida, substitui pelo valor
|
||||||
|
new_label = " ".join([account_dict.get(name, name) for name in pattern_parts])
|
||||||
|
account_dict["label"] = new_label
|
||||||
|
|
||||||
|
accounts_settings.append(account_dict)
|
||||||
|
|
||||||
|
result = ""
|
||||||
|
|
||||||
|
if config.get("add-ghost"):
|
||||||
|
result += GHOST_TEMPLATE
|
||||||
|
|
||||||
|
current_account_template = ACCOUNT_TEMPLATE
|
||||||
|
|
||||||
|
if not config.get("set-template") is None:
|
||||||
|
current_account_template = Path(config.get("set-template")).read_text(encoding="utf-8")
|
||||||
|
|
||||||
|
for account in accounts_settings:
|
||||||
|
new_entry = current_account_template
|
||||||
|
# Substitui todas as variáveis encontradas
|
||||||
|
for var_name, value in account.items():
|
||||||
|
new_entry = new_entry.replace("$" + var_name, str(value))
|
||||||
|
|
||||||
|
result += new_entry.strip() + "\n"
|
||||||
|
|
||||||
|
result = result.strip()
|
||||||
|
|
||||||
|
# Numeração sequencial das contas [Account1], [Account2]...
|
||||||
|
id = 1
|
||||||
|
while "Account_" in result:
|
||||||
|
result = result.replace("Account_", f"Account{id}", 1)
|
||||||
|
id += 1
|
||||||
|
|
||||||
|
output_file.write_text(result, encoding="utf-8")
|
||||||
|
print(f"Sucesso: {id-1} contas criadas em '{output_file}'.")
|
||||||
|
|
||||||
|
main()
|
||||||
Loading…
Reference in New Issue