I am trying to build a badge system that is similar to StackOverflow in my entity-framework code-first application.
I will have around 10 badges in total and each type of badge has its own properties. I am thinking to have base class Badge and derive the other classes from the base class.
For example, there will be Sprinkle badge and it will be automatically assigned to the user if his post is liked 3 times or more. So, I will have Sprinkle class with additional property NumberOfLikes (so that it can be updated later). However, in the database table, there will be only one record for this class. Isn't this weird?
I will have 10 classes like this, and there will be only single record for their corresponding table in the database. I have to have separate classes for each to be able to configure their unique properties.
Is my design choice a poor one?
You may consider to differentiate between the business rule of the badge, that is coded in the derived badge class and the bookkeeping of earned badges of a user. I see no need to have this rule classes be entity framework classes and to store them in the database if it does not have any parameters you want to change frequently. You could store this parameters in other configuration stores (eg. exe.config) or similiar or hardcode it. The (perhaps only one) instance of this classes are purely to execute the business rule. See them as services (DDD) or perhaps strategy pattern or (for evaluation) visitor pattern. They could just be created (perhaps per IoC/Di container that automatically creates all derivations) without storing/loading in the database.
On the other hand you have to bookkeep which user earned which badge (it could be a performance hit to calculate this new on every request). Here it makes sense to have a class that is stored in the database (1:n) and stores the list of badges a user received. So after every change (new post, new like, whatever) or from time to time (nightly run) you run through your badge rule classes and every badge the user does not already have (or if it is possible to loose a batch you take all) is executed for this user to check if it applies. If yes, the marker is created that the user earned the badge.
In your example, you may store in your database the user, his post and the number of likes. The Sprinkle badge could be a result of some business rules (is your post (or user) Sprinkle compatible) and may not be stored in your database?
In other worlds, the Sprinkle badge is a way to see a post (or a user) having more than 3 likes?
Maybe this rules could be stored in your database and parametrized?
Related
Say I have two entities
Notifications and Users.
I want to mark that a user has seen a specific notification.
This would commonly be done with a many-to-many relationship
e.g. UserNotification
Because there is no invariant around this relationship (we don't care if "all" users have seen the notification) these users shouldn't be on the notification aggregate.
On the opposite side, the users aggregate doesn't need a list of notifications on it
So that leads to say that the UserNotification (this relationship) is an aggregate of its own.
However, because we are never going to reference this thing by Id, does it really really belong as one? It seems like just adding an aggregate for storing the data.
What should I do here?
Just make an aggregate anyway and ignore the id?
Put these notifications on the user or users on notifications. (does it belong on either, and would putting it on one not add weight and cause concurrency issues?)
just make a crud table?
An aggregate without the id and keep the composite key (is that allowed?)
thanks
Does a Notification have its own lifecycle? Can a Notification exist without a User to be notified?
I could imagine a Notification to simply be a Value Object that gets copied to each affected User.
have you considered modeling User and Notification as aggregates but NOT modelling the association at all?
There is a high probability of not needing to. The only usecase I can come up with is retrieving all notifcations of a user. this can be exposed in an repository interface via getNotifications(user: User): Iterable[Notifications] (scala syntax).
on the write side the saveNotification(notification: Notification, users: List[User]) could save the aggregate as well as populate the n:m table.
EDIT: on afterthought to this - my solution would introduce a source code dependency from notifications to users (at least on the repository) and your intiuition might be right - the notification should not know about the user at all.
But there has to be at least the concept of an Recipient which may perfectly reside in the notification "module" or "package". maybe you are crossing bounded contexts here and the User entity on one side should be translated to an Recipient value object on the other via Anti Corruption Layer.
It's up to you and your domain to decide. In this example it would perfectly make sense that the notification package has some knowledge about a "User". otherwise - what would be notified?
I'm building a SaaS project using Symfony2, Doctrine2 and Postgresql. I have three different subscription plans, and for each plan there is a limit of members each user can store.
How can I limit a user to not store more members that the allowed for his subscription plan? Should I use a pre-persist event, counting the number of records belonging to her, and if there is an excess of records cancel the operation? Or this should be in the model or in the controller?
I recently had to build the same type of functionality for shouttag.com, where a user can only register X number of shouttags dependent upon their current billing plan. Granted, I am using Symfony/Doctrine 1.x, but the approach should be identical. Put the logic in the model layer, and whenever a user attempts to link a new member (via form save for example), issue a query for the user's current subscription plan, and how many members they currently have, if the resulting number is >= their allowed limit, then they cannot add more members until they change their subscription plan.
As an over-arching design goal you want to keep your controllers lean, and put most of your logic into your models (skinny controllers, fat models), this way the logic can be shared elsewhere throughout your code-base.
I've been thinking about the applications for goangular. In the need for immediate storage/database updates, such as a chat application or stocks application etc., I can see how goangular can be extremely useful in the sense of SignalR methodologies. But could it be applied to the traditional form with ten fields and a save button on it? All I could think of, was the traditional form, with ten fields on it -less the save button. If all ten fields are on the scope of the controller, than there would be no need for a save button. Every change of a field would be commemorated to the goinstant storage. Now having said that, how would one UNDO lets say any changes to those ten modified fields? Control+Z ten times? Not so robust. Any ideas on a UNDO all Changes button for such a form? (desperately trying to expand the bonds of real time database transactions)
I'll attempt to answer what I believe to be the spirit of your question first.
Most of the time, when using GoAngular, we're focused on synchronizing application state. Aka: Active clients sharing session data. Inevitably we drift into the territory of long-term persistence. At this point, rigorous validation / sanitization become a necessity, which we can't discuss without some context.
Let's say our user is completing their profile. This profile will be used to create a User model, which we will persist. Now that we have context, it becomes clear that we shouldn't persist a partially complete form, because it wouldn't represent a valid User model. We persist the form once it is complete, and valid.
Implementing this is as simple as creating a custom $scope.onSubmit method and validating the form input before calling $save on our new $scope.user model.
Undo would be easy to implement too, if you use $scope.users.$add, a key will be generated and returned, you could use this key to remove the new user. If you wanted to roll-back a change, you'd need to implement some system for versions, and roll back to the previous version of that User.
Hope I've answered your question in here somewhere :)
Is it possible to programmatically create a new version of a CQ5 page that has a start time some time in the future?
As an example, let's say we have a page that displays tax rates. We have a component that allows the author to upload a new rates table (in the form of a css file) and it creates the rates page content. We would like to allow the author to upload rates that will be effective the first of next month.
I know the jcr supports multiple versions of nodes, but its unclear how (or whether) this relates to cq5 page versioning. And, further, whether a new version can be activated in the future.
Given the requirements as you've described them, I would probably accomplish the task in a slightly different way...
Instead of storing my rates table information directly within the page's jcr:content node (or a sub node their of) I'd probably abstract it out to somewhere else in the repository. You could then, if you so desired, create some sort of an admin interface to allow content authors to upload their csv file of new rates, and ingest that into the repository as needed. Alternatively, assuming that data comes from some sort of a database, you could probably just write a job to automatically injest it on some sort of a scheduled basis by using a JDBC connection from CQ. Once the data is in the repository, you could then write the display component to read the data from the repository, instead of it being directly inside the page.
This approach has the advantage of making that data re-useable within CQ to be shown on multiple pages, multiple sites, even many different display formats if need be. In addition, you can design your jcr structure to support whatever requirement you have around updates to the data, including daily, monthly, weekly, yearly etc., obviously this will depend on the specific requirements.
The one downside to this is that since there is a separation b/w the data and the page(s) where it is displayed, you may need to find a way to ensure the cache is properly cleared whenever the data does change.
Update (based on your comment):
The problem I foresee with versioning the page, and granted I've not tried this so maybe it will work, is that there can only ever be one active version at a time. Therefore, once the next months data is uploaded, you need to maintain the old data (active) and the new data (not yet active) at the same time. What happens if you require a separate content change during that window...from a business process perspective that just seems messy to me.
Back to cache clear issues, If you know the affected pages, especially if they are all in one subtree, you could write a custom workflow process that uses the replicator service to clear the cache for the affected pages, then set up a launcher to run the wf on node change for the data.
The other option, and this one is less defined in my head, so some experimentation required, would be to use CQs built in activate later and de-activate later functionality.
Maybe create a specific template for the rates data, with the implicit requirement that only one page using that template is ever active at one time. Your display components could use a query to find the currently active rates data.
I have not personally tried this, but...
I assume that you can use the PageManager service's createRevision method, and then if that returns without throwing an exception, you may call page.getContentResource.adaptTo(Node.class), and from there take the node that is returned and edit the JCR properties for your tax rates component.
See PageManager
You could write a workflow that includes a publish step that is triggered by the arrival of a calendar date. The version of the page with the new tax rates remains in the workflow pipeline in draft form and is only published/activated when the date arrives. (So you'd need some sort of process that wakes up once a day to check the calendar.)
Each time a page is modified cq creates a version of the page.
This modified page's modification time is set in jcr:lastModified property of the page.
Manipulation of this property can be done to save future date and activate page on that date though its not preferred way.
You can store the future date as a property in the page.
Later as suggested by #David you can create a workflow or a scheduled job which activates pages with a future date.
I'm using Catalyst with Catalyst::Plugin::Authentication and
Catalyst::Plugin::Authorization::Roles and am wondering if there is a better
approach to adding an attribute to a model that I'm not seeing.
Each user is permitted to access one or more companies, but there is
always one primary (current) company at a time. The permitted list is
stored in the database, and database access is primarily through DBIC.
My first inclination is to say that it's the user that has a current
company, and thus put it as part of the user model: give the user
package a "sub company { … }" to get/set the user's current company. The
database check is fairly easy; just use "$self->search_related" (a DBIC
method, inherited by the user model).
The problems I run in to are:
The current company needs to persist between requests, but I'd rather
not store it to the database (it should only persist for this
session). The natural place is the session…
There is a role, akin to Unix's root, that allows you to act as
any company, ignoring the list in the database. Checking this role
can be done through the database, but everywhere else in the app uses
$c->assert_user_role and friends.
I've heard its best to keep the models as Catalyst-independent as
possible. It also seems pretty weird to have a model manipulating
$c->session.
Of course, I could move those checks to the controllers, and have the
model accept whatever the controller sends, but that's violating DRY
pretty heavily, and just begging for a security issue if I forget one of
the checks somewhere.
Any suggestions? Or do I just shrug and go ahead and do it in the model?
Thanks, and apologies for the title, I couldn't come up with a good one.
The key is to create an instance of the model class for each request, and then pass in the parts of the request you need. In this case, you probably want to pass in a base resultset. Your model will make all the database calls via $self->resultset->..., and it will "just work" for the current user. (If the current user is root, then you just pass in $schema->resultset("Foo"). If the current user is someone else, then pass in $schema->resultset("Foo")->stuff_that_can_be_seen_by($c->user). Your model then no longer cares.)
I have some slides about this, but they are very outdated:
http://www.jrock.us/doqueue-grr/slide95c.html#end
(See the stuff immediately before and after, also.)
Note that restricted resultsets and web ACLs are orthogonal. You want to make the model as tight as possible (so that your app can't accidentally do something you don't want it to, even if the code says to), but various web-only details will still need to be encoded in ACLs. ("You are not allowed to view this page." is different from "You can only delete your own objects, not everyone's". The ACL handles the first case, the restricted resultset handles the second. Even if you write $rs->delete, since the resultset is restricted, you didn't delete everything in the database. You only deleted the things that you have permission to delete. Convenient!)