\section{Implementação}
Neste capitulo descrevemos alguns aspetos que achamos mais relevantes a nível de implementação. Tanto a nível de cliente, como de servidor, foram surgindo alguns desafios e aqui descrevemos alguns deles e a abordagem tomada em cada caso.

\subsection{Cliente}
No cliente, para além das ferramentas usadas detalhadas em cima, os pontos mais relevantes é a reutilização de componentes. Sempre que algum componente é utilizado para mostrar dados semelhantes, estes foram adaptados de maneira a que possam ser usados em vários contextos. Como exemplo mostramos o componente \textit{TablueCourses}, que é utilizado para mostrar as edições atuais de um aluno, os resultados de um aluno e as edições atuais de um professor.

\vspace{0.5cm}
\begin{lstlisting}[caption=ToubleCourse, language=JavaScript]
var TableCourses = React.createClass({

	getInitialState:function(){
		return {
			open: false,
			data: null,
			type: null,
			course_data: null
		}
	},

	componentDidUpdate: function(){
		var type = this.props.list_type;
		
		if(this.props.student != null && this.state.data != null && (type == null || type != this.state.type)){
			if(type == "currentCourses")
				this.getCurrentEdition(this.props.student.number);
			else if(type == "finishedCourses")
				this.getCoursesResults(this.props.student.number);
		} else if(this.props.professor != null && this.state.data != null && (type == null || this.state.type)){
			this.getProfessorEditions(this.props.professor.id);
		}

	},
	
	....
	
	getCoursesResults: function(number){
		var self = this;
		$.get('/student/view/'+number+'/results', function(data) {
			self.setState({data:data, type:self.props.list_type});
		});
	},

	getCurrentEdition: function(number){
		var self = this;
		$.get('/student/view/'+number+'/editions',function(data){
			self.setState({data:data,type:self.props.list_type});
		});
	},

	getProfessorEditions: function(number){
		$.get("/professor/view/"+number+"/editions", function (data) {
			this.setState({data:data});
		}.bind(this));
	},
	
	...
}

\end{lstlisting}


\subsection{Servidor}

No servidor, o desafio maior foi a parte referente à segurança. Como tínhamos um formulário de Login construido em React que executava um POST por ajax, a abordagem foi um pouco diferente da exemplificada nas aulas.

Na classe \textit{SecurityConfig.java} adicionamos algumas operações necessárias e implementamos os métodos de duas classes (\texit{AuthenticationSuccessHandler} e \textit{AuthenticationFailureHandler})

A ideia foi definir dois \textit{handlers} para o caso de sucesso ou falha na autenticação. Nesta configuração também são protegidas as rotas consoante se podem ser acedidas por professores, estudantes ou assistentes.

\begin{lstlisting}[caption=SecurityConfig classe, language=Java]
    
 @EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
	
	@Autowired
	private UserDetailsService users;
	@Autowired
	AuthenticationFailure customAuthFailure;
	@Autowired
	AuthenticationSuccess customAuthSucc;
	
	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http
			.csrf().disable()  
			.authorizeRequests()
				.antMatchers("/img/**", "/js/**", "/").permitAll()
				.antMatchers("/student/**").hasRole("STUDENT")
				.antMatchers("/edition/**").hasAnyRole("PROFESSOR","STUDENT")
				.antMatchers("/professor/**").hasAnyRole("PROFESSOR","ASSISTANT").and()
			.formLogin()
				.permitAll()
				.loginPage("/login")
				.successHandler(customAuthSucc)
				.failureHandler(customAuthFailure).and()
			.logout().logoutSuccessUrl("/").and()
			.exceptionHandling().accessDeniedPage("/").and();
	}

	@Autowired
	public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
		auth.userDetailsService(users).passwordEncoder(new BCryptPasswordEncoder());
	}
}
    
\end{lstlisting}

Nesta classe reimplementamos o método que é chamado em caso da autenticação ser sucedida. Como temos vários tipos de conta, fazer a autenticação não chega, pois embora um utilizador seja autenticado, temos que garantir que está a ser autenticado no local autorizado. Neste método é verificado que a conta existe e se a entidade que fez autenticação é um estudante ou um professor. Caso a conta exista e seja do tipo professor ou estudante então é colocado um parâmetro no \textit{reponse header} com o nome de \textit{redirect}. Este parâmetro é acedido na resposta no lado do cliente para sabermos para que pagina deverá ser reencaminhado depois da autenticação.

\begin{lstlisting}[caption=AuthenticationSuccessHandler interface, language=Java]

@Component
public class AuthenticationSuccess extends SimpleUrlAuthenticationSuccessHandler {

	@Autowired
	AppService service;

	@Override
	public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
			Authentication authentication) throws IOException, ServletException {

		String username = request.getParameter("username");
		Account ac = service.getAccountByUsername(username);

		if (ac != null) {
            AccountRole accRole = ac.getRole().getDescription();
            if (accRole.equals(AccountRole.STUDENT)) {
				Student s = service.getStudentByAccount(ac);
				response.addHeader("redirect", "/student/" + s.getNumber());
			} else if (accRole.equals(AccountRole.PROFESSOR) || accRole.equals(AccountRole.ASSISTANT)) {
				Professor p = service.getProfessorByAccount(ac);
				response.addHeader("redirect", "/professor/" + p.getId());
			}
        } else {response.sendError(500, "Account doesn't exist");}
	}
}
\end{lstlisting}

Esta classe é o inverso da descrita a cima. Quando a autenticação falha é enviado \textit{status code 500} para o cliente.

\begin{lstlisting}[caption=AuthenticationFailureHandler interface, language=Java]

@Component
public class AuthenticationFailure extends SimpleUrlAuthenticationFailureHandler{

	@Override
	public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
			AuthenticationException exception) throws IOException, ServletException {
		
		response.sendError(500, "Authentication Failed");
	}

}

\end{lstlisting}

Foi necessário a implementação destas classes, pois a autenticação usada foi por \textit{request} em ajax, e consoante a resposta do servidor o cliente decide o que fazer. O comportamento de autenticação por formulário acaba por redirecionar automaticamente para uma pagina (de erro ou principal) e não era esse o comportamento desejado.

De notar, que cada entidade (Student, Professor) no nosso modelo de base de dados tem uma conta (Account) e que cada conta está associada a um tipo de role (PROFESSOR, STUDENT, ASSISTANT). Sendo que cada role tem permissões diferentes. Para controlar estas permissões foram criadas anotações aos pedidos nos controladores.

Como por exemplo, um estudante editar a sua informação pessoal. Partimos do princípio que apenas o próprio estudante pode editar as suas informações pessoais.

\begin{lstlisting}[caption=Exemplo de anotação de segurança, language=Java]
@RequestMapping(value = "/edit/{number}", method = RequestMethod.POST)
	@PreAuthorize("hasRole('STUDENT') and @securityService.isStudentPage(#number)")
	public @ResponseBody ResponseEntity<?> editStudent(@PathVariable int number, @RequestParam Map<String, String> requestParams){...}
\end{lstlisting}

Finalmente neste capítulo, existem algumas anotações que achamos relevantes comentar. Como por exemplo, confirmar se a entidade pode aceder a um determinado pedido verificando o seu tipo de conta. Mas também se, mesmo que o tipo de conta seja válido, essa entidade tem responsabilidade sobre o recurso pretendido. Como é o caso de um professor só poder dar notas se a entidade autenticada for do tipo Professor e caso seja professor dessa edição. Estas verificações são feitas na classe \textit{SecurityService}.

\vspace{2cm}
\begin{lstlisting}[caption=Exemplo de verificação de segurança, language=Java]
@Service
public class SecurityService {

	@Autowired
	AppService service;

	public boolean isStudentPage(final int number) {
    	User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
    	try {
			Student student = service.getStudentByNumber(number);
			Account a = student.getAccount();
            if (a.getUsername().equals(user.getUsername()))
				return true;
            return false;
        } catch (Exception e) {return false;}
	}
	
	public boolean isProfessorOfEdition(final Long eid){
		
		User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();

		try{
			Account a = service.getAccountByUsername(user.getUsername());
			Professor prof = service.getProfessorByAccount(a);
			for(Edition e : prof.getEditions()){
				if(e.getId() == eid)
					return true;
			}
			return false;
		}catch(Exception e){
			return false;
		}	
	}
	...
}
\end{lstlisting}