Category Archives: T.I.

Tutoriais, Problemas e Reclamações do mundo de TI

Validando campos no SQLAlchemy (Python) com decorators, no estilo Java Bean Validation

Já faz uns 4 anos que decidi experimentar Python e não deu outra: foi paixão arrebatadora. Mas algumas funcionalidades de outras linguagens e bibliotecas despertam saudades, uma delas foi o Bean Validation do Java EE.

Em um projeto que decidi usar Flask, Flask-Restless e SQLAlchemy, senti falta de algo parecido para fazer as validações de campos. O SQLAlchemy tem um decorator para validar campos, mas você precisa escrever dentro da função a validação. Para auxiliar na tarefa, criei uma biblioteca, chamada osirisvalidator, com decorators para auxiliar nessa validação.

Você pode clonar o código fonte em: https://github.com/davidaug/osirisvalidator (e contribuir com novas validações) ou instalar pelo comando:

pip install osirisvalidator

Sintaxe

Vamos considerar a classe User, que é um objeto Model do SQLAlchemy:

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True, nullable=False)
    email = db.Column(db.String(120), unique=True, nullable=False)
    cpf = db.Column(db.String(11), unique=True, nullable=False)

Para validar um campo no SQLAlchemy, é necessário fazer uma função com o decorator @validates , passando o nome do campo e criando os parâmetros key e value na função alvo.

 class User(db.Model):

    [...]

    @validates('email')
    def validate_email(self, key, email):
        return email

Mais informações em: https://docs.sqlalchemy.org/en/13/orm/mapped_attributes.html

Com o osirisvalidator, podemos adicionar os decorators já prontos, como no exemplo abaixo:

from osirisvalidator.internet import valid_email

[...]
class User(db.Model):

    [...]

    @validates('email')
    @not_blank(field='email')
    @valid_email(field='email', message='email deve ser válido!')
    def validate_email(self, key, email):
        return email

O USO DO “@validates(‘nomecampo’)” É OBRIGATÓRIO!

O parâmetro “field” no decorator é obrigatório, e “message” é opcional, sendo que todas as validações já possuem uma mensagem padrão. Outros validadores possuem atributos próprios, como o osirisvalidator.string.string_len e o osirisvalidator.string.match_regex :

    @validates('telefone')
    @is_digit(field='Telefone')
    @string_len(field='Telefone', min=10, max=11)
    def validate_telefone(self, key, telefone):
        return telefone
    @validates("sexo")
    @match_regex(field='Sexo', regex=r'^[FMfm]$', message='Sexo deve ser F ou M')
    def validate_sexo(self, key, sexo):
        if sexo is not None:
            return sexo.upper()

Exemplo Completo em Flask

Para facilitar o entendimento, criei um script já completo utilizando Flask, basta instalar as dependências, que estão descritas no requirements.txt e rodar o arquivo app.py.

https://github.com/davidaug/osirisvalidator-flask-example

Caso seja encontrado algum erro de validação, uma ValidationException é disparada e é possível disponibilizar o erro ao consumidor:

except ValidationException as ve:
    return jsonify({"status": 400, "message": "erro de validação!", "errors": ve.errors}), 400

O osirisvalidator funciona em conjunto com o SQLAlchemy, logo, pode ser utilizado em qualquer lugar para validação de campos, incluindo uma aplicação Qt.

Validadores Implementados

osirisvalidator.string

  • not_empty
  • not_blank
  • is_alpha
  • is_alpha_space (alpha characters and space)
  • is_alnum
  • is_alnum_space (alphanumeric characters and space)
  • is_digit
  • string_len (mandatory parameters: min and max)
  • match_regex (mandatory parameter: regex)

osirisvalidator.number

  • min_max (mandatory parameters: min and max)
  • not_null

osirisvalidator.internet

  • valid_email

osiris.intl.br

  • valid_cpf
  • valid_cnpj

Upload Ajax de Imagem com Preview no Primefaces

Um problema que me deu dor de cabeça:
Fazer upload de imagem via ajax e dar um preview, utilizando o componente fileupload do Primefaces. Já estava me sentindo derrotado com o problema.

O componente é bizonho, (Spoiler alert!) ele não funciona fora de um SessionScoped . Mas, como sou guerreiro, e como a arquitetura da minha aplicação precisa de ManagedBeans com ViewScoped , Entoado por canções de cunho moral, eu insisti e consegui contornar o problema.

Outro alerta de spoiler:
Ainda não testei em plenos vapores de ambiente de produção, se alguém encontrar um erro, por favor relate e talvez em menos de um ano eu responda.

Primeiro passo:

Criar um ManagedBean, do tipo SessionScoped :

@ManagedBean
@SessionScoped
public class ImageBean {
	
	StreamedContent st;
	
	public void uploadImagem(byte[] imagem){
		
		st = new DefaultStreamedContent(new ByteArrayInputStream(imagem));
		
	}
	
	public StreamedContent getSt() {
		return st;
	}
}

Nesse ManagedBean, incluímos um objeto StreamedContent , que vai possibilitar o preview da imagem no  componente graphicimage do Primefaces, e um método que recebe um bytearray que é a imagem. No caso, esse método pode ser adaptado, eu estou utilizando um tipo bytearray porque gravo a imagem no banco.

Depois disso, vamos tratar do nosso ManagedBean da página:

@ManagedBean
@ViewScoped
public class CadastrarPessoaBean {

	@EJB
	PessoaFacade pessoaFacade;
	
	@ManagedProperty(value="#{imageBean}")
	ImageBean imageBean;

	Pessoa pessoa = new Pessoa();

	public void anexaArquivo(FileUploadEvent event) {

		try {
			this.pessoa.setFoto(IOUtils.toByteArray(event.getFile().getInputstream()));
			imageBean.uploadImagem(this.pessoa.getFoto());
		} catch (IOException e) {
			/* Joga alguma mensagem na tela! */
		}

	}

}

Aqui, criei um método chamado anexaArquivo, este método vai primeiro, popular meu objeto Pessoa para salvar a foto em banco, e depois vai popular o ImageBean.

Por fim, adicionamos os componentes nas páginas, e é só aproveitar a magia:

<h:panelGroup id="imagemJogador">
	<p:graphicImage id="foto_jogador" style="max-width: 300px;max-height: 300px;" cache="false" value="#{imageBean.st}">
	</p:graphicImage><br/>
</h:panelGroup>

<p:fileUpload fileUploadListener="#{jogadorCadastrarBean.anexaArquivo}"
mode="advanced" showButtons="false" label="#{lang.procurar}"
update="imagemJogador" auto="true" sizeLimit="#{jogadorCadastrarBean.maxSize}"  allowTypes="/(\.|\/)(gif|jpe?g|png)$/" ></p:fileUpload>
 <p:growl id="messages" showDetail="true" />

Vejam só, o componente p:fileUpload possui um método chamado fileUploadListener, que foi colocado no ManagedBean da página, e o componente p:graphicImage busca o StreamedContent lá no Imagebean

É claro isso é um exemplo cru, eu deixei desta forma para que fique simples e fácil de entender(Eu acho). Algo direto, dentro disso você pode(e DEVE) garantir validações de arquivo, tamanho de arquivo, e etc. dentro do ManagedBean.

Gerador de Nicks

(Se você não deseja ler toda a baboseira, vá direto ao pote de ouro: http://gerador-davidaug.rhcloud.com/geradordenicks/)

Se você está na fissura para jogar, e não tem criativiade para criar um nick? Aí está a oportunidade.

Evidente que tudo é muito non-sense, mais baseado em humor do que seriedade e pode gerar algum nick sem nenhum sentido para humanos(non-sense?), porém foi este gerador que forneceu meu nick na steam(Darth Risovaldo) .

Aí está o link novamente pra você que não leu nada a não ser isso:
http://gerador-davidaug.rhcloud.com/geradordenicks/

Se você quer descobrir a história e a moral, continue lendo:

Continue reading

MaskTextField para JavaFX

Estou desenvolvendo um software em JavaFX, e essa é a primeira vez que utilizo essa tecnologia(Também ainda não conheço todas as suas ferramentas de fato). De começo foi amor à primeira vista, ainda mais com a arquitetura de FXML editados no JavaFX SceneBuilder e um Controller.

Porém, nem tudo é perfeito, e num determinado momento precisei de máscaras nos Text Fields, o que não é implementado nativamente. Pesquisa daqui, pesquisa lá, não achei nada que realmente me agradasse, então coloquei a mão na massa e criei um MaskTextField.

A classe está em: https://github.com/davidaug/masktextfield

Recentemente fiz um vídeo para ajudar um pouco: https://youtu.be/P2kBxpLkDZc

Continue reading