Aprendendo a montar um site com SailsJS. Escolhi por criar o projeto RateSite. Esse programa terá dois usuários padrão. Um prestatador de serviço e um cliente. Exemplo de uso: Chaveiro/Cliente; Médico/Paciente; Possuidor de Carro/Cliente; Manicure/Cliente ....
- Implementar o Passport básico criado por Giancarlo Soverini e uma explicação geral por toon.io - commit
- Criar uma tela que apenas logados podem entrar (com logout) - commit
- Criar uma mensagem de erro para o usuário, informando que ele não está logado - commit
- Noob: O nome dessa mensagem e flash() - req.flash()
- Info: O Chrome volta e meia manda dois POSTs iguais, com isso as vezes mando um flash duplicado. Não consegui impedir de passar na policy a segunda vez.
- Info: A maioria dos flash() que criarei no projeto serão no próprio cliente (quando eu usar o AngularJS), não preciso de um modelo muito complexo.
- Eu quero fazer um req.flash() e req.redirect('/') na policies/isAuthenticated.js
- Eu pensei em usar a proposta de um serviço 'FlashService' + política 'flash', mas acho que é mais complexo do que eu preciso, i.e. temos que adicionar a policy sempre antes de outras policies que precisam do flash, e principalmente, não podemos fazer um flash e redirect() como era o objectivo. 6. Acabei usando a ideia do req.flash() simples. Criando um partial EJS para cuidar disso - alterei o EJS da resposta para fazer para um for no req.flash() [mais robusto]
- Enviar o password encriptado para o servidor.
- Vou continua enviando plain text porque usamos HTTPS
- Explicação¹
- Javascript Cryptography
- Criar esqueci minha senha
- Etapas: (Usuário pede para resetar senha em /forgotPassword) -> (Servidor Envia email) -> (Usuário redefine a senha passando como parâmetro o token recebido no email) -> (Servidor atualiza a senha e invalida token). Segui o tutorial do Sahat Yalkabov.
- Permitir mandar email. Utilizei o sails-hook-email (tive muito problema de timeout. Acho melhor usar a API do mailGun) - commit
- Para as configurações do Email (principalmente a senha) não ficarem no repositório, eu as coloquei no config.local que não é versionado por default.
- Eu estava com problema para enviar email pelo Gmail. Para resolver eu ativei o 2-steps verification e adicionei um 'App Password'. Também tentei usar o Mailgun
- Permitir resetar a senha e verifica se o token expirou Criar token com expiration - commit
- Criar login pelo Google commit
- Seguir os passos para criar seu app no Google API - Tutorial do Jenkins
- Implementar o Google Auth via passport-google-oauth seguindo o tutorial do sails-social-auth-example e o tutorial do Michael Herman
- Note que não precisamos fazer o google/callback porque o controller pega todos os google/* FIX
- Me ajudou ler essa pergunta do Stackoverflow
- Alterei o User porque o beforeUpdate estava fazendo o hash do hash da senha - commit
- Me ajudou um issue do Sails-REST-API
Começaremos a parte de negócio que cria o conceito de Empregado (Employer) e Prestador de Serviço (Employee). O prestador de serviço deve definir a sua área de atuação. Também será criado o conceito de comentários, que possui um Empregado, um Prestador de Serviço, uma classificação e o texto do comentário.
- Criar o Employer e Employee - commit
- Todos os usuários possuem um Employer por padrão (criado no
beforeCreate()
do User). O Employee é criado na tela principal quando o usuário está logado (Dashboard). - Na realidade o User possuirá dois perfis um como Employer e outro como Employee e terá um relacionamento de um para um
- O Employee possui uma área de atuação
workingRegion
específica. Atualmente oworkingRegion
está em formato de string. No futuro podemos criar um Model Região e permitir uma relacionamento um para vários. - Criamos a política
policies/insertUserId.js
que adiciona o usuário logado (userID) dentro da requisição enviada (body.param do POST). Peguei ideia do Tarmo Leppänen via Gitter e pelo Código.
- Todos os usuários possuem um Employer por padrão (criado no
- Criar a busca pelos Employees - commit
- Preferi criar um serviço de busca que é responsável por ter o algoritmo de busca. Inicialmente criei apenas a busca pelo prestador de serviço
- O EmployeeController é responsável apenas por organizar o request para o serviço e criar o response para o usuário
- Criei uma view simples com postback mesmo. A pesquisa ficou na área privada (dashboard) e o resultado em uma página a parte.
- Criar a estrutura de Review - commit
- Um review possui um comentário e um rating, e tem um relacionamento de um para um com um cliente e um prestado de serviço.
- Escolhi colocar o rating como um número de 1 a 4. Note que o review terá um rating com quantidades de escolhas pares. Gostei dessa abordagem por obrigar ao usuário a escolher um lado, removendo opiniões neutras ou sem opiniões - exemplo
- Nesse commit, apenas de eu criar o RatingService, eu não estou fazendo o cálculo médio do rating. Farei no próximo commit.
- Adicionar o MongoDB - commit
- Segui o tutorial do Ponzi Coder que utiliza sails-mongo
- Depois criei os usuários root e rateServerName e depois rodei o mongod com
--auth
- tutoral - Por segurança, eu coloquei o usuário e senha no config/local.js:
connections: { mongodb: { user: 'MY_NAME', password: 'MY_PASSWORD_WITHOUT_@_CHAR', } }
- Bom tutorial do MongoDB
- Fazer o cálculo do rating cache dos prestadores de serviço corretamente - commit
- Criei o serviço
services/RatingService.js
para tratar dos cálculos de rating dos Prestadores de serviço - Atualmente estou fazendo uma média simples para determinar o rating do prestador de serviço
- Eu escolhi deixar um cache porque imaginei que o cálculo de rating pode ser muito custoso para ser executado a todo momento - eu precisaria de todos os reviews de cada usuário
- Achei melhor criar uma serviço, a deixar no controller, porque:
- Quero que um job execute a tarefa de recalcular o rating de todos os usuários
- Podemos ter ratings de outros models
- Podemos ter um algoritmos mais complexos que leve em conta a expertise do usuário ou a relevância do voto e etc. - exemplo de cálculo do IMDB
- Criei o serviço
- Criar o cachedRating como uma tarefa externa - commit
- Ter o cache do rating do Prestador de serviço otimiza bastante o tempo de resposta do servidor para responder requisições de pesquisa. Por outro lado, me obriga a criar uma terefa para recalcular o cache em algum momento.
- Para resolver esse problema eu optei por utilizar o sails-hook-jobs, que utiliza o projeto Agenda do rschmukler e possui persistência do MongoDB. Outra opção seria o sails-hook-schedule ou node-schedule ou node-cron. Discussão interesante sobre Scheduler no Sails
- Para a instalação do hook eu segui os passos do manual
- Eu escolhi deixar como padrão o scheduler como disable, em config/hooks.js. Se quiser ligar bastar colocar na configuração ou no locals.js
hooks: {"jobs": true}
. Também pode desabilitar uma tarefa específica viadisable: true
dentro da configuração do próprio job. - Para configurar o mongoDB (que já está estou usando no projeto e com --auth) segui os passos:
show databases use jobs db.createUser( { user: "JobScheduler_SailsServer", pwd: "MY_PASSWORD", roles: [ { role: "root", db: "admin" } ] } );
- Como o sails provê uma forma de levantar um servidor que não execute nenhum request (via sails.load() exemplo, eu consigo levantar um servidor sails que execute unicamente as tarefas/jobs.
- [minor] Criar a política policies/insertData que utilizo para debug de request - commit
- Adiciona reCAPTCHA - commit
- Utilizei a biblioteca reCAPTCHA2, segundo o tutoral com tranquilidade
- Como todas as outras senhas, eu as coloquei no config/locals.js
O Sails aconselha utilizar para os testes o Mocha com Chai. Li um artigo bem básico que explica muito bem o Mocha + Chai. De qualquer forma achei muito confuso, porque existem 1000 soluções na web e achei difícil encontrar um exemplo completo com explicação - com teste de serviço, mock de serviço e etc.
- Segui os passos do Sails/Testing e com o exemplo do Tarmo Leppänen e albertosouza - commit
- Mesmo com muita informação, o passo-a-passo do Sails resolveu bem
- Só precisei aprender o que eu precisava instalar; alterar o banco de dados para o
localDiskDb
; desativar os hooks que não são necessários para reduzir o tempo de inicialização do Sails
- Criar um configuração para o teste e adicionar alguns testes - commit
- Criar uma
config/env/test.js
para deixar as configurações específicas dos testes - Estou utilizando o sails-memory
- Como a configuração do
config/local/js
é prioridade de todas as configurações, coloquei como prioridade notest/bootstrap.test.js
o log comosilent
- Criar uma
- Criar um teste com Mock do serviço utilizado no Modelo - commit
- Para testar a criação do User foi necesário utilizar um mock do serviço de autenticação, já que o
User.beforeCreate()
utiliza um CAPTCHA. - Tomei como base no artigo do Sergio Cruz
- Usei o sinon
- Estou usando um drop no after() para limpar o banco de dados, mas nessa pergunta temos outra solução http://stackoverflow.com/questions/26063827/drop-the-entire-sails-memory-database
- Para testar a criação do User foi necesário utilizar um mock do serviço de autenticação, já que o
- Criar um teste de integração nos Controller - commit
- Para facilitar os testes, estou usando o supertest
- Atualizar o teste para utilizar o Chai - commit
- Atualizei um teste apenas para demostrar o uso do Chai.
- Preferi utilizar o
expect()
, entendi que evita possíveis erros quando a variável é undefined
- Criar um exemplo que dependa de uma base de dados (fixtures) - commit
- Estou usando os
fixtures
para carregar um conjunto de usuários a serem criados - Texto interessante
- Durante os meus testes eu tive problema com "after all hook", i.e. test.bootstrap.after(), que só possui a linha
sails.lower()
. Eu abri um ticket no Sails. Como eu acredito que o lower está chamando a callback antes de finalizar todos os processos, eu adicionei umsetTimeout(done, 1000);
. Essa linha pode sair quando o problema for resolvido.
- Estou usando os
- Continuar os testes para 100% de cobertura - incompleto para sempre
Fase 5 Usar o Angular, de preferência usar esse projeto como back apenas e um front em angular separado Colocar Validações no cliente
- Para o front/CSS pensei em usar Foundation, mas depois de estudar um pouco decidi deixar a parte de design para depois. Não tenho competência para isso no momento.
- Utilizei async para algumas tarefas ao invés de callback diretamente - tutorial. Pessoalmente eu prefiro Promise que já uso no angular.js, mas as libs são feitas com callback, por isso preferi utilizar o async a usar uma Promise com wrapper
Eu não consegui usar o config/local.js
, nem o config/env/*.js
dentro do config/passport.js
. Gostaria de usa-lo para salvar o appURL e o GoogleAPI.
Depois de algum estudo, verifiquei que o Sails não tem um suporte 100% para esse tipo de uso. Então decidi colocar o appURL (variável com a URL) como uma variável do ambiente APP_URL="http://falcon-medico-makah.c9users.io:8080/" sails lift
- preferia ter colocado em config/env/*
. commit
Já o GoogleAPI eu coloquei o workarround require(./local)
- Stackoverflow
Podemos usar o Waterline via callback .exec() ou via promise .then(), como eu prefiro usar a Promise, optei pelo .then() - até ai tudo bem. A questão é que o .then() me retorna uma Bluebird Promise, mas isso não quer dizer que eu posso criar uma Promise sem adicionar a biblioteca no meu projeto - eu tenho acesso ao objecto Promise já criado, não à bibilioteca. Pata ter acesso eu adicionei o Bluebird no projeto e adicionei o requre("Bluebird")
.