Niby o piłce, a na Daj się poznać, czyli Morena Gdańsk – Karlikowo Sopot

Zaczyna się runda wiosenna polskiej ligi, więc pora nieco przyspieszyć prace nad Matchloggerem, żeby dało się zapisywać swoje mecze. Miałem dzisiaj okazję być na B-klasowym derby Trójmiasta pomiędzy Moreną Gdańsk, a Karlikowem Sopot. O samym meczu nie napiszę jednak za wiele, jeśli ktoś ma ochotę dowiedzieć się więcej, to polecam albo relację na regiowyniki.pl, albo album ze zdjęciami z meczu zrobionymi przeze mnie. Opowiem za to co nieco o różnych sposobach patrzenia na mecz i tym, jak te sposoby mają się do procesu wytwarzania oprogramowania.

Uwaga, post zawiera zdjęcia o łącznej wadze kilkunastu MB. Przed przejściem na „czytaj dalej” upewnij się, że korzystasz z Wi-Fi, jesteś na kablu albo masz odpowiednio duży pakiet transferu danych.

Matchlogger update: I can add teams now!

I did quite a lot today. From working login, I went to being able to add teams through the user interface. All code changes can be seen in today’s pull request.

Tables and entity classes for countries and teams

I started with a database table for country information. I decided that this one will be (for now) managed only through Liquibase changesets, as I expect that country list will be static. For the beginning, there’s only one country (Poland), but I already have a task to add more. Each of the countries consists of name, some country codes (ISO-3166-1, FIFA, IOC) and a link to flag picture from Wikimedia Commons.

My structure for teams starts simple and is likely to grow. We’ve got a name, country and a link to team’s crest (logo). Right now I don’t store pictures, just links to them. This will likely change in future, but that requires a decision on how to store them – something that is a good topic for another post 🙂

Vue.js attempt

I must admit that I had some issues with Vue.js. My first idea was to create a REST API returning team list, load them with Vue.js and present records in a table with Angular-like syntax. I must have overlooked that before, but it turns out that core Vue cannot trigger AJAX calls and needs to use a separate library for that. One has several options, starting with vue-resource, up to jQuery. I decided to start with jQuery, as I already was importing it for Bootstrap JS features. Turned out that fighting with what it looked like a simple „for each row print <tr> and three <td> tags” took me three hours after which I decided that for this module, I will go the known way and implement it with Thymeleaf.

With Thymeleaf, the structure of the application is different. We don’t provide a REST API but insert needed values on backend side using a Model object instead. The templating engine works fairly similar to what I wanted with Vue.js though, so while I don’t remove Vue yet, I’ll start with Thymeleaf and read more on Vue in the meantime.

Thymeleaf layout

Thymeleaf has its benefits – one of them is a fragment-based layout. I now have a structure where layout.html defines the core layout and each of pages doesn’t have to include a header, footer, core CSS and JS files all over again. Of course, as I’m a lazy developer that wants to start with something that looks decent and is responsive, I started with Bootstrap that I aim to customize when I get the functional part done.

So, how does the team list look like?

The user is able to add a new team, define a country (from a long list that includes Poland, Poland and… Poland), add a link to a crest picture and that’s it. Not much, but it is a first real functional part of the application. More to come soon.

Spring Boot: Saving OAuth2 login data in DB using PrincipalExtractor

This post is a continuation of configuring OAuth2 login in Spring Boot. If you want to know how to configure the login itself, please take a look at the previous post.

As I mentioned previously, we want to save user login data in our database to be able to connect matches data with their users. We’re going to save only some basic data – the external id of the user from the provider to distinguish the user, her full name (that I want the user to be able to replace it with the nickname in the future), avatar and e-mail address. Let’s start with the database. As we already configured Liquibase, we are able to add a migration that will create the table in the DB:

As we have only one provider now, we could as well skip the login_type column. That would mean that if we add a new provider, we’d likely need to add this column and prepare migration that adds the value for existing records, so I decided that it’s a good idea to start with it. When we now start the application, the table is created in the database:

Next step is adding User entity class and its related Repository interface we’ll be using for DB access. As I wanted to use LocalDateTime for managing dates, but JPA doesn’t work that well with it yet, I needed to add Jsr310JpaConverters class to @Entityscan in my MatchloggerApplication class.

The last part was using PrincipalExtractor to obtain the data we want, actually save them into the database and mark that they will be used as principal data. The documentation of this class is virtually non-existent, but I found this example. I added a similar section to my WebSecurityConfiguration.java with just returning the same I received to check which data I am able to obtain.

That was the set of data provided by PrincipalExtractor. It appears that everything that I wanted to get is available here, but there is one potential issue I may come up with in future – as long as I have only one authentication provider, I know that those data come from Google, but if I have several providers and they provide different data, it might be the case that I’ll need to find out the provider based on some keys’ existence. Not the best option, but seems I need to stick with it for now (if anybody knows a better option, please let me know).

My WebSecurityConfiguration class looks like this now:

After adding the PrincipalExtractor, I am able to see that on successful login I have my first user in the database.

Let’s then modify the code that returns user data to use my new configuration:

After login, this is a current message that we see:

One note to add is that Java 8 LocalDateTime doesn’t look too nice in generated JSON response. I’ll likely convert the returned value into a timestamp in the future, depending on view layer’s needs.