20/02/2018 Development / java script

Trabalhar com firebase é muuuuuuuuuuuuuuito produtivo! Super rapido fazer as paradas, subir aplicação, mas tem 2 coisas que eu vi que são chatinhas, uma eu já citei aqui que é o lance de não ter um JOIN decente no database, a outra, porém é necessário, é que a gente só consegue manipular os dados de usuários através do servidor. No client, não é possível fazer um firebase.auth().getUser(uid) por exemplo, e tem total sentido isso né!

Então, acaba que a gente tem que meter a mão na massa e fazer as Cloud Functions, que são tipos umas funções que você vai poder executar do lado do servidor. Nesse caso, eu precisei meeeeeesmo, fazer um CRUD pra manipular os dados de usuários. Então eu vou compartilhar com vocês. É só trocar a chave da public key, fazer o deploy e correr pro abraco!

const express = require('express');

const app = express();

const functions = require('firebase-functions');

const admin = require("firebase-admin");

const bodyParser = require('body-parser');

const cors = require('cors');

 

app.use(cors({ origin: true }));

app.use(bodyParser.urlencoded({ extended: true }));

app.use(bodyParser.json());

 

admin.initializeApp({

  credential: admin.credential.cert({

    projectId: "AQUIVEMSEUPROJETO",

    clientEmail: "AQUIVEMOSEUEMAILPROVADO",

    privateKey: "-----BEGIN PRIVATE KEY-----AQUIVEMASUACHAVEPRIVADA==\n-----END PRIVATE KEY-----\n"

  }),

  databaseURL: "https://AQUIVEMOSEUPROJETO.firebaseio.com"

});

 

//GET

app.get('/:id', (req, res) => {

let uid = req.params.id;

admin.auth().getUser(uid)

  .then(function(userRecord) {

    resp.json(userRecord.toJSON());

  })

  .catch(function(error) {

    res.json(error);

  });

});

 

//POST

app.post('/', (req, res) => {

let data = req.body;

console.log(data);

 

admin.auth().createUser(data)

  .then(function(userRecord) {

    res.json(userRecord);

  })

  .catch(function(error) {

    res.json(error);

  });

});

 

//DELETE

app.delete('/:id', (req, res) => {

let uid = req.params.id;

admin.auth().deleteUser(uid)

  .then(function(userRecord) {

    res.json(userRecord.toJSON());

  })

  .catch(function(error) {

    res.json(error);

  });

});

 

//UPDATE

app.put('/:id', (req, res) => {

let uid = req.params.id;

let data = req.body;

admin.auth().updateUser(uid, data)

  .then(function(userRecord) {

    res.json(userRecord.toJSON());

  })

  .catch(function(error) {

    res.json(error);

  });

});

exports.api = functions.https.onRequest(app);

Espero que sirva!

20/02/2018 Development / macetes

Agora no bootstrap 4 existe uma série de classes utilitarias, aquelas classes que são uma mão na roda. Uma delas é pra margin e padding e funciona da seguinte maneira.

m = margin
p = padding

e as combinações são

m-0, m-1, m-2, m3, m-4, m-5, sendo que m-0, tira completamente a margin e as outras você vai adicionado 15% da aréa da margin.

E tem tambem a possibilidade de setar a posição da margin. Ex: mt-0 isso é o margin-top. Entao temos: mt, mb, ml, mr

E por fim se quisermos deixar centralizado a margin, usamos o mx-auto!

A mesma coisa serve para o padding ;-)

Espero que ajude!

02/02/2018 Database / sql server

Essa dica é pra quem quer fazer uma query SQL Server e quer que ela seja disponilizada via JSON.

Usar inner join, com inner join e mais inner join, é uma Merda!

Ex: usando inner join 

SELECT     imovel.cod, 
           imovel.referencia, 
           medias.idmedia, 
           medias.txtpath, 
           h.txatividade 
FROM      [hfbimoveis-bkp].[dbo].[tabImovel] imovel 
INNER JOIN tabmedia medias 
ON         ( 
                      imovel.cod = medias.codimovel) 
INNER JOIN tabimovelhistorico H 
ON         h.codimovel = imovel.cod 
WHERE      imovel.cod = 1133 FOR json auto

[
{"cod":1133,
"referencia":"CL107",
"medias":[
{
"idMedia":3925,
"txtPath":"Cittá Fachadas (4)_640x480.jpg",

"H":[
{"txAtividade":"Cadastrou o Laudo"},{"txAtividade":"Atualizou o Laudo"},{"txAtividade":"Atualizou o Laudo"},{"txAtividade":"Atualizou o Laudo"},{"txAtividade":"Atualizou o Laudo"},{"txAtividade":"Atualizou o Laudo"},{"txAtividade":"Atualizou o Laudo"},{"txAtividade":"Atualizou o Laudo"},{"txAtividade":"Atualizou o Laudo"},{"txAtividade":"Atualizou o Laudo"},{"txAtividade":"Atualizou o Laudo"},{"txAtividade":"Atualizou o Laudo"},{"txAtividade":"Atualizou o Laudo"},{"txAtividade":"Atualizou o Laudo"},{"txAtividade":"Atualizou o Laudo"},{"txAtividade":"Atualizou o Laudo"},{"txAtividade":"Atualizou o Laudo"}]}]}]

Olha oque aconteceu? O meu historico foi parar dentro das MEDIAS! Errado neh

Por isso, é preferível fazer usando select, dentro de select

SELECT imovel.cod, 
       imovel.referencia, 
       ( 
              SELECT m.idmedia, 
                     m.txtpath 
              FROM   tabmedia M 
              WHERE  m.codimovel = imovel.cod FOR json auto) AS m, 
       ( 
              SELECT h.txatividade 
              FROM   tabimovelhistorico AS h 
              WHERE  h.codimovel = imovel.cod FOR json auto) AS h 
FROM   [hfbimoveis-bkp].[dbo].[tabImovel] imovel 
WHERE  imovel.cod = 1133 FOR json auto

[
{"cod":1133,
"referencia":"CL107",
"m":[{"idmedia":3925,"txtpath":"Cittá Fachadas (4)_640x480.jpg"}],
"h":[
{"txatividade":"Cadastrou o Laudo"},{"txatividade":"Atualizou o Laudo"},{"txatividade":"Atualizou o Laudo"},{"txatividade":"Atualizou o Laudo"},{"txatividade":"Atualizou o Laudo"},{"txatividade":"Atualizou o Laudo"},{"txatividade":"Atualizou o Laudo"},{"txatividade":"Atualizou o Laudo"},{"txatividade":"Atualizou o Laudo"},{"txatividade":"Atualizou o Laudo"},{"txatividade":"Atualizou o Laudo"},{"txatividade":"Atualizou o Laudo"},{"txatividade":"Atualizou o Laudo"},{"txatividade":"Atualizou o Laudo"},{"txatividade":"Atualizou o Laudo"},{"txatividade":"Atualizou o Laudo"},{"txatividade":"Atualizou o Laudo"}]
}]

As medias ficaram em 1 linha, e os historicos ficaram em outra linha!

Espero que isso ajude, tanto quanto me ajudou ;-)

 

02/02/2018 Development / ferramentas

Com certeza, se alguém precisar exportar os dados de uma tabela SQL Server para JSON, o pulo do gato é isso aqui! BCP

BCP é uma linha de comando que transforma uma consulta SQL no arquivo txt ou arquivo que vc deseja. Então pra executar é a seguinte parada:

Abra a sua linha de comando, no meu caso é o prompt do DOS e digite:

bcp "SELECT * FROM [hfbimoveis-bkp].[dbo].[tabImovel] FOR JSON AUTO" QUERYOUT "C:\data\arquivo.txt" -S HUGGLER\SQLEXPRESS -T

Nesse caso, eu ainda usei outro pulo do gato, que foi o FOR JSON AUTO, essa porrinha transforma o resultado da consulta em formato JSON :-))))))))))

Obs: No prompt do DOS vão aparecer algumas perguntas:

Digite o tipo de armazenamento: Você digita -> cr
Insira o comprimento do prefixo: Você digita -> 0
Insira o comprimento do campo: Você digita -> 0
Insira o terminador: Dê enter

E pronto, na sua pastinha C:\data\arquivo.txt estará seu JSON bonitinho, depois é só formatar e correr para o abraço!

 

30/01/2018 Development / java script

Essa parada do firebase não ter um join, innerjoin, groupBy, é meio frustante, então, eu vou descrever aqui, oque eu tenho feito para suprir as minhas necessidades.

O firebase tem um evento listener chamado ON e ONCE, onde você pode aplicar alguns valores:

let ref = firebase.database().ref();

ref.child('livros').on('child_added', => snapshot { console.log(snapshot.val()); })
ref.child('livros').on('value', snapshot  => { console.log(snapshot.val()); })
ref.child('livros').on('child_removed', snapshot => { console.log(snapshot.val()); })
ref.child('livros').on('child_changed', snapshot => { console.log(snapshot.val()); })

A diferença entre ON e ONCE é que ONCE escuta uma vez só, e ON fica escutando sempre.

Seguindo essa documentação, imagina que eu tenho uma LISTA de LIVROS, e pra cada LIVRO eu gostaria de trazer o AUTHOR e todo mundo que já comprou esse livro.

Bom, com SQL ou até mesmo com MONGO, isso seria uma tarefa fácil, mas com essa porra de firebase, já é chatinho, mas vamo la!!!

No cenário mais simples, a gente usuário o child_added, que pra cada livro a gente iria consultar o author e os clientes. Vamos fazer a query

ref.child('livros').on('child_added', => snapshot {
let livro = snapshot.val();
let authorId = livro.authorId;
console.log('nome do livro: ' + livro.nome);
ref.child('author').orderByChild("authorId").equalTo( authorId ).on('value', author => {
console.log('nome do author:' + author.val().nome;
})
})

Sabe oque aconteceria nesse caso? Primeiro, ia dar o console.log de todos os nomes dos nossos livros e depoooooois, iria dar o console do nome dos autores. Ex:

nome do livro é: SENHOR DOS ANEIS
nome do livro é: O ALQUIMISTA
nome do livro é: TUDO É POSSÍVEL

nome do author: J. R. R. Tolkien
nome do author: Paulo Coelho
nome do author: Allan Percy

Mas oque a gente queria fazer é:

nome do livro é: SENHOR DOS ANEIS
nome do author: J. R. R. Tolkien

nome do livro é: O ALQUIMISTA
nome do author: Paulo Coelho

nome do livro é: TUDO É POSSÍVEL
nome do author: Allan Percy

Ai você pensa: Ahhhhhh, fácil, no retorno da segunda consulta eu mostro o nome do livro junto com o nome do author :-), Que malandro sou eu? hummmmm

ref.child('livros').on('child_added', => snapshot {
let livro = snapshot.val();
let authorId = livro.authorId;

ref.child('author').orderByChild("authorId").equalTo( authorId ).on('value', author => {
console.log('nome do livro: ' + livro.nome + '\n');
console.log('nome do author:' + author.val().nome;

})
})

Tá, assim funciona! Mas e agora no caso da gente adicionar o terceiro listener, que é o caso dos clientes que compraram, oque a gente pode fazer? Ao mesmo tempo que você esta consultando o author, também esta consultando os clientes, você não sabe qual vai ser o primeiro ou último a responder, por isso não pode jogar o console no listener do author ou no listener do cliente, certo?

Nesse caso, usamos o conceito de Promisse() e ao inves de ON, usamos o ONCE que retorna uma Promisse, e a implementação ficaria da seguinte maneira:

Só uma observação: Quando a gente usa orderByChild, é como se fosse um filtro, então, ele retorna um array podendo conter 1 ou mais objetos.

let promises = [];

ref.child('livros').on('child_added', => snapshot {
let livro = snapshot.val();
let authorId = livro.authorId;

let promise_author = ref.child('author').orderByChild("authorId").equalTo( authorId ).once('value') //no caso do author, vai trazer 1 só
let promise_pedidos = ref.child('pedidos').orderByChild("livroId").equalTo( livroId ).once('value') //no caso de pedidos, vai trazer varios, 1 pedido contem o codigo do cliente e codigo do livro e como o pedido é um snapshot de como estão as informações no momento. Aprendi isso trabalhando na B2W! Pra mim oque vale é o nome do cliente naquele dia.

promises.push(promise_author, promise_pedidos) //inserindo as promises na fila

// Quando terminar todas as minhas promises, ai sim eu monto a resposta final

Promise.all(promisses).then(function(resp){

let nomeLivro = livro.nome;
let nomeAuthor = resp[0].val().nome;
let clientePedidos = resp[1].val().map(pedido => { return pedido.nomeCliente });

      array.push(livro.nome + ' - ' + nomeAuthor + ' - ' + clientePedidos.join('\n'))

     $('pre').text(array.join('\n'))

    })

})

Essa foi a saida para a implementação usando uma espécie de JOIN, claro que ao inves de colocar no ARRAY, eu fiz um objeto bonitinho, mapeado, e tal, mas isso fica a critério da sua implementação. Espero que sirva de base!

 

Em 2010 eu inicie um projetinho na faculdade que era um sistema simples de gerenciamente do imóveis. Basicamente é um dashboard onde o cliente insere informações e na outra ponta, o cliente consegue visualizar as informações, imagens, valor, etc...

A primeira versão foi feita em ASP, SQL Server, CSS, JS Puro... No dashboard eu usei EXTJS pra construir o layout e os componentes. Além disso eu implementei um sistema bem TOSCO de notificação em tempo real. O sisteminha fica chegando de N em N segundos se tem algum registro novo no banco e emit um alerta pra todo mundo.

Bom, são 8 anos que se passaram e até agora nenhum cliente reclamou, mas eu tenho uma mania que querer deixar meus projetos sempre atualizados, então esse ano eu decidi refazer a porra toda.

A principio eu escolhi pelas seguintes tecnologias:

  • ANGULAR 5 tanto no front do website, quanto no dashboard administrativo;
  • MongoDB como banco de dados - Eu ia escolher firebase, mas essa parada de não ter 1 mínimo relacionamento descente é foda, eu sofri pra caramba num projeto que eu tive que fazer os relacionamentos na mão;
  • Bootstrap como framework de layouts e componentes;
  • E o sistema de notificação usando Socket.

Basicamente é isso, eu estou começando hoje dia 30/01/2018 e vamos ver quanto tempo eu vou levar pra finalizar esse projetinho.

Tarefas pra fazer no novo sio

  1. combobox de tipos, subtipos, zonas
  2. combobox de selecao de proprietarios
  3. combobox de selecao de loja
  4. maskaras de valor
  5. combox de selecao de corretores
  6. historico de acoes
  7. upload de imagens
  8. pegar cep automaticamente
  9. mapa do google
  10. grid com paginacao e filtros

 

13/12/2017 Development / java script

Eu uso com muuuuuita frequencia essa parada, então, deixar registrado aqui pra eu poder usar com mais facilidade.

A primeira é essa porrinha aqui, pra pegar somente os números: "ABABABABAAB12121212-232323fdfdf".replace(/\D/g, '')

A outra é pra formatar moeda antes de salvar no banco de dados.

Ex: "R$ 15.404,00" (STRING) se eu salvar assim direto, depois fica ruim de formatar.

Entao é bom salvar assim => Number("R$ 15.404,00".replace(/[^0-9\.]+/g,""))

Espero que me ajude :-)

 

08/12/2017 Development / java script

this._$state.transitionTo('titulos', this._$stateParams, { reload: true, inherit: false, notify: true });

Espero que ajude!

04/12/2017 Development / css

div {

  font: 70px -apple-system;

  animation-name: 'doughnuts';

  animation-duration: 3s;

  animation-iteration-count: infinite;

  animation-direction: alternate;

}

 

@keyframes doughnuts {

from {

font-variation-settings: "wght" 1;

}

to {

font-variation-settings: "wght" 1.98;

}

}

02/12/2017 Development / java script

angular.module('myUtils', [])
.factory('$Utils', ['$rootScope', function($rootScope){

  this._$scope = $rootScope;

  var NormalizedCollection = (ref, childKey, keyValue, obj) => {
    ref.child(childKey).once('value').then(resp => {
        obj[keyValue] = resp.val();
        this._$scope.$apply();
    });
  };

  return {
    NormalizedCollection : NormalizedCollection
  };
}]);

angular.module('MyOtherApp', ['myUtils']);

export class MyController {
  constructor ($Utils) {}
}