1. Overview
In this article we're going to be building a Profile for the user of our Reddit application – to allow them to configure user specific preferences.
The goal is simple – instead of having the user fill in the same data each time they schedule a new post, they can set it once – in the preferences of their profile. Of course the user can always tune these settings for each post – but the idea is they don't have to.
2. The Preference Entity
Overall, most things that can now be configured in the applications are going to become globally configurable in the user profile.
First, let's start with a Preference entity:
@Entity
public class Preference {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String email;
private String subreddit;
private boolean sendReplies;
// for post re-submission
private int noOfAttempts;
private int timeInterval;
private int minScoreRequired;
private int minUpvoteRatio;
private boolean keepIfHasComments;
private boolean deleteAfterLastAttempt;
}
So, what can we now configure? Simply put – defaults for pretty much every setting in the application.
We're also storing the email of the user to allow them to receive notifications about what's happening to their posts.
Now, let's link the preferences to the user:
@Entity
public class User {
...
@OneToOne
@JoinColumn(name = "preference_id")
private Preference preference;
}
As you can see, we have a simple one-to-one relation between User and Preference.
3. Simple Profile Page
First, let's create our simple profile page:
<form >
<input type="hidden" name="id" />
<input name="email" type="email"/>
<input name="subreddit"/>
...
<button onclick="editPref()" >Save Changes</button>
</form>
<script>
$(function() {
$.get("user/preference", function (data){
$.each(data, function(key, value) {
$('*[name="'+key+'"]').val(value);
});
});
});
function editPref(){
var data = {};
$('form').serializeArray().map(function(x){data[x.name] = x.value;});
$.ajax({
url: "user/preference/"+$('input[name="id"]').val(),
data: JSON.stringify(data),
type: 'PUT',
contentType:'application/json'
}).done(function() { window.location.href = "./"; })
.fail(function(error) { alert(error.responseText); });
}
</script>
Nothing fancy here – just some plain HTML and JavaScript.
Let's also add a quick link to the new profile:
<h1>Welcome, <a href="profile" sec:authentication="principal.username">username</a></h1>
4. The API
And here the controller, for creating and editing user's preferences:
@Controller
@RequestMapping(value = "/user/preference")
public class UserPreferenceController {
@Autowired
private PreferenceRepository preferenceReopsitory;
@RequestMapping(method = RequestMethod.GET)
@ResponseBody
public Preference getCurrentUserPreference() {
return getCurrentUser().getPreference();
}
@RequestMapping(value = "/{id}", method = RequestMethod.PUT)
@ResponseStatus(HttpStatus.OK)
public void updateUserPreference(@RequestBody Preference pref) {
preferenceReopsitory.save(pref);
getCurrentUser().setPreference(pref);
}
}
Finally, we need to make sure that, when the user is created, its preferences are also inintialized:
public void loadAuthentication(String name, OAuth2AccessToken token) {
...
Preference pref = new Preference();
preferenceReopsitory.save(pref);
user.setPreference(pref);
userReopsitory.save(user);
...
}
5. Load/Use Preferences
Now – let's see how to use these preferences and fill them in whenever they're required.
We'll start with the main Post Schedule page – where we'll load in the preferences of the user:
$(function() {
$.get("user/preference", function (data){
$.each(data, function(key, value) {
$('*[name="'+key+'"]').val(value);
});
});
});
6. Testing and Conclusion
We're almost done – we just need to implement some basic integration tests for the new Profile entity we just introduced.
For the most part, we're simply going to be extending the existing base persistence test and inherit a battery of tests from that.
Finally – we can wrap up the new user profile functionality – users are now able to set up their own preferences.