Getting user that initiated push to pre-receve hook - atlassian-plugin-sdk

I´m developing a pre-receive hook with the atlassian-plugin-sdk and I need to get the user name of the user who pushed the changes. So what I want to get inside the hook is what I locally can get with 'git config user.name', is that possible?

Use AuthenticationContext to get the current authenticated user. See the example:
#Component
public class BlockInvalidRefPreReceiveRepositoryHook extends TaboolaBaseHook implements PreRepositoryHook<RepositoryHookRequest> {
private final AuthenticationContext authenticationContext;
#Autowired
public BlockInvalidRefPreReceiveRepositoryHook(#ComponentImport AuthenticationContext authenticationContext) {
this.authenticationContext = authenticationContext;
}
#Nonnull
#Override
public RepositoryHookResult preUpdate(#Nonnull PreRepositoryHookContext preRepositoryHookContext,
#Nonnull RepositoryHookRequest repositoryHookRequest) {
if (!isValidTrigger(repositoryHookRequest.getTrigger())){
return RepositoryHookResult.accepted();
}
ApplicationUser currUser = this.authenticationContext.getCurrentUser();
for (RefChange refChange : repositoryHookRequest.getRefChanges()) {
if (refChange.getType() == RefChangeType.ADD && refChange.getRef().getType() == StandardRefType.TAG) {
// Allow only specific user to push tags
if (currUser.getType() == UserType.NORMAL && !currUser.getName().equals("validUserToPushTags")) {
return RepositoryHookResult.rejected("Only user validUserToPushTags is able to push tags",
"Only user validUserToPushTags is able to push tags");
}
}
}
return RepositoryHookResult.accepted();
}
}

I assume you are making a bitbucket plugin. You can get commit information by registering a CommitCallback to the PreRepositoryHook. Below code is untested, but it should fetch the author of a commit.
public class CommitMessageHook implements PreRepositoryHook<RepositoryHookRequest> {
#Nonnull
#Override
public RepositoryHookResult preUpdate(#Nonnull PreRepositoryHookContext context, #Nonnull RepositoryHookRequest request) {
// hook only when a commit is added to the repository
context.registerCommitCallback(
new CommitCallback(),
RepositoryHookCommitFilter.ADDED_TO_REPOSITORY);
return RepositoryHookResult.accepted();
}
private static class CommitCallback implements PreRepositoryHookCommitCallback {
private RepositoryHookResult result = RepositoryHookResult.accepted();
#Nonnull
#Override
public RepositoryHookResult getResult() {
return result;
}
#Override
public boolean onCommitAdded(#Nonnull CommitAddedDetails commitDetails) {
Commit commit = commitDetails.getCommit();
Person author = commit.getAuthor();
String authorName = author.getName();
return true;
}
}
}

Related

How to create a BitBucket hook that reject pushes with bad file name?

I'm trying to make a BitBucket hook that would reject a push if it contained a file not matching a naming convention. So far, I'm able to create a PreRepositoryHook implementation that register the following callback.
public class MyPreRepositoryHook implements PreRepositoryHook<RepositoryHookRequest> {
public MyPreRepositoryHook () {
}
#Nonnull
#Override
public RepositoryHookResult preUpdate(#Nonnull PreRepositoryHookContext context,
#Nonnull RepositoryHookRequest request) {
// hook only wants commits added to the repository
context.registerCommitCallback(
new MyPreCommitCallback(),
RepositoryHookCommitFilter.ADDED_TO_REPOSITORY);
// return accepted() here, the callback gets a chance to reject the change when getResult() is called
return RepositoryHookResult.accepted();
}
In MyPreCommitCallback:
#Override
public boolean onCommitAdded(#Nonnull CommitAddedDetails commitDetails) {
Commit commit = commitDetails.getCommit();
SimpleChangeset.Builder builder = new SimpleChangeset.Builder(commit);
SimpleChangeset simpleChangeset = builder.build();
Page<Change> changes = simpleChangeset.getChanges();
}
But I am unable to get the list of files since the call to simpleChangeset.getChanges always return null.
Any help in getting a list of file names would be appreciated. Thank you.
#Component
public class AltresPreRepositoryHook implements PreRepositoryHook<RepositoryHookRequest> {
private final CommitService commitService;
#Autowired
public AltresPreRepositoryHook(#ComponentImport CommitService commitService) {
this.commitService = commitService;
}
private static class AltresPreCommitCallback implements PreRepositoryHookCommitCallback {
private final RepositoryHookRequest request;
private final CommitService commitService;
private RepositoryHookResult result = RepositoryHookResult.accepted();
public AltresPreCommitCallback(RepositoryHookRequest request, CommitService commitService) {
this.request = request;
this.commitService = commitService;
}
#Nonnull
#Override
public RepositoryHookResult getResult() {
return result;
}
#Override
public boolean onCommitAdded(#Nonnull CommitAddedDetails commitDetails) {
Commit commit = commitDetails.getCommit();
ChangesRequest.Builder builder = new ChangesRequest.Builder(commit.getRepository(), commit.getId());
ChangesRequest changesRequest = builder.build();
final ChangedPathsCollector changedPathsCollector = new ChangedPathsCollector();
commitService.streamChanges(changesRequest, changedPathsCollector);
Collection<String> changedPaths = changedPathsCollector.getChangedPaths();

Injecting/Managing at runtime changing connectionstrings using Entity Framework, Dependency Injection, Unit of Work and Repository Patterns

The situation
I'm building a web application using the in the title mentioned techniques. This application will something like a CMS system for multiple clients. The client has to login to this system using his company name and login credentials.
With the provided company name, I connect to a database (static DbContext, same connection string every time) where all clients database information is stored and search for this clients specific database(every client has his own with exact same design) login information. That all works fine.
Now here is the tricky part. To continue the login procedure I need to somehow inject or lazy load the repository using the other DbContext with a connection string that is build up from the result of the other database.
What I have
2 DbContexts generated from an existing database, one static and one if possible dynamic.
Then the generic repository classes/interfaces:
public interface IRepository
{
void Submit();
}
public interface IRepository<TEntity, TContext> : IRepository
where TEntity : class
where TContext : DbContext
{
//crud stuff
}
public abstract class GenericRepository<TEntity, TContext> : IRepository<TEntity, TContext>
where TEntity : class
where TContext : DbContext
{
private TContext _dataContext;
private IUnitOfWork _unitOfWork;
private readonly IDbSet<TEntity> dbset;
protected GenericRepository(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
_unitOfWork.Register(this);
}
}
Unit of work class/interface
public interface IUnitOfWork
{
void Register(IRepository repository);
void Commit();
}
public class UnitOfWork : IUnitOfWork
{
private readonly Dictionary<string, IRepository> _repositories;
private HttpContextBase _httpContext;
public UnitOfWork(HttpContextBase httpContext)
{
_httpContext = httpContext;
}
public void Register(IRepository repository)
{
_repositories.Add(repository.GetType().Name, repository);
}
public void Commit()
{
_repositories.ToList().ForEach(x => x.Value.Submit());
}
}
Then a context/entity specific repository
public class EmployeeRepository : GenericRepository<tbl_Medewerker, CustomerDbEntities>, IEmployeeRepository
{
public EmployeeRepository(IUnitOfWork unitOfWork)
: base(unitOfWork)
{
}
}
public interface IEmployeeRepository : IRepository<tbl_Medewerker, CustomerDbEntities>
{
}
Then the service that implements the repository
public interface IEmployeeLoginService
{
tbl_Medewerker GetEmployeeByLogin(string username, string password);
tbl_Medewerker GetEmployeeByID(Guid id);
}
public class EmployeeLoginService : IEmployeeLoginService
{
private readonly IEmployeeRepository _employeeRepository;
public EmployeeLoginService(IEmployeeRepository employeeRepository)
{
_employeeRepository = employeeRepository;
}
public tbl_Medewerker GetEmployeeByLogin(string username, string password)
{
return _employeeRepository.Get(e => e.MedewerkerNaam.ToLower() == username.ToLower() && e.Password == password);
}
public tbl_Medewerker GetEmployeeByID(Guid id)
{
return _employeeRepository.GetById(id);
}
}
Finally the controller that implements that service and uses it in the login action
public class AccountController : BaseController
{
IConnectionService _connectionService;
IEmployeeLoginService _employeeService;
public AccountController(IConnectionService connectionService, IEmployeeLoginService employeeService)
{
_connectionService = connectionService;
_employeeService = employeeService;
}
[AllowAnonymous, HttpPost]
public ActionResult Login(LoginModel login)
{
if ((Settings)Session["Settings"] == null)
{
Settings settings = new Settings();
settings.company = _connectionService.GetCompanyName(login.CompanyName);
if (settings.company != null)
{
settings.licence = _connectionService.GetLicenceByCompanyID(settings.company.Company_id);
if (settings.licence != null)
{
settings.connectionStringOrName = string.Format(#"Data Source={0};Initial Catalog={1};User ID={2};Password={3};Application Name=EntityFrameworkMUE", settings.licence.WS_DatabaseServer, settings.licence.WS_DatabaseName, settings.licence.WS_DatabaseUID, settings.licence.WS_DatabasePWD);
Session["Settings"] = settings;
settings.user = _employeeService.GetEmployeeByLogin(login.UserName, login.Password);
if (settings.user != null)
{
FormsAuthentication.SetAuthCookie(string.Format("{0},{1}", settings.company.Company_id.ToString(), settings.user.Medewerker_ID.ToString()) , login.RememberMe);
return RedirectToAction("index", "home");
}
}
}
}
else
{
return RedirectToAction("index", "home");
}
return View();
}
}
And of course the autofac bootstrapper:
private static void SetAutoFacContainer()
{
var builder = new ContainerBuilder();
builder.RegisterControllers(Assembly.GetExecutingAssembly());
builder.RegisterType(typeof(UnitOfWork)).As(typeof(IUnitOfWork)).InstancePerHttpRequest();
builder.RegisterAssemblyTypes(typeof(UserRepository).Assembly)
.Where(t => t.Name.EndsWith("Repository"))
.AsImplementedInterfaces().InstancePerHttpRequest();
builder.RegisterAssemblyTypes(typeof(ConnectionService).Assembly)
.Where(t => t.Name.EndsWith("Service"))
.AsImplementedInterfaces().InstancePerHttpRequest();
builder.Register(c => new HttpContextWrapper(HttpContext.Current)).As<HttpContextBase>().InstancePerLifetimeScope();
builder.RegisterModule(new AutofacWebTypesModule());
builder.Register(att => new AuthorizeFilter(att.Resolve<IConnectionService>(), att.Resolve<IEmployeeLoginService>())).AsAuthorizationFilterFor<Controller>().InstancePerHttpRequest();
builder.RegisterFilterProvider();
IContainer container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
}
My idea how to do this, is setting a session variable with the connection string after data retrieval from the one static database where the info is stored and inject session in the unit of work and somehow use it there, but I can't wrap my head around it.
The question(s):
Am I heading in the right direction trying to achieve this, or even is it possible? If not what steps would you take to achieve this
I know it's a long read I hope you guys can help me, I'm quite new to using these techniques all together. Thanks in advance - I really appreciate it!
Your on the right track, I have used
var mtc = new MultitenantContainer(container.Resolve<ITenantIdentificationStrategy>(), container);
DependencyResolver.SetResolver(new AutofacDependencyResolver(mtc));
The identification strategy would be based on the logged in user. With defaults for when they aren't logged in.
public class CompanyNameIdentificationStrategy : ITenantIdentificationStrategy
{
public bool TryIdentifyTenant(out object tenantId)
{
var context = HttpContext.Current;
if(context != null)
{
var myUser = context.User as MyUserObject;
if(myUser != null)
{
tenantId = myUser.CompanyName;
return true;
}
}
return false;
}
}
Then you add to your autofact setup:
var s = c.Resolve<ITenantIdentificationStrategy>();
object id;
if (s.TryIdentifyTenant(out id) && id != null)
{
return id;
}
return "default";
}).Keyed<string>("CompanyName");
builder.Register<Settings>(c =>
{
var companyName = c.ResolveKeyed<string>("companyName");
if (companyName == "default")
{
return new DefaultSettings();
}
var settings = new Settings();
return settings;
}).InstancePerLifetimeScope();
You can resolve stuff inside these code blocks. I would probably setup a keyed default settings, and then when the user is logged in the settings would switch to their setup and the rest of the application should work.

Why canReveal() of GateKeeper was called before the EventHandler was called (GWT)?

I got a Header presenter which is the nested presenter. The Customer presenter is the child of Header presenter (ie the Customer presenter was put into a slot of Header presenter).
So I want to use MyGateKeeper to manage login page. The HeaderPresenter that will fire PassUserInfoEvent.
public class MyGateKeeper implements Gatekeeper{
private String loginedUserID="";
private final EventBus eventBus;
#Inject
public MyGateKeeper (final EventBus eventBus){
this.eventBus = eventBus;
this.eventBus.addHandler(PassUserInfoEvent.getType(), new PassUserInfoHandler(){
#Override
public void onPassUserInfo(PassUserInfoEvent event) {
// TODO Auto-generated method stub
String userID=event.getUserID();
loginedUserID=userID;
}
});
}
#Override
public boolean canReveal(){
System.out.println(loginedUserID+"Test");
if(!loginedUserID.equals("")){
System.out.println(loginedUserMeaningID+"cxcxc");
return true;
}
else{
return false;
}
}
}
In the CustomerPresenter:
#ProxyCodeSplit
#NameToken(NameTokens.cust)
#UseGatekeeper(MyGateKeeper.class)
public interface MyProxy extends ProxyPlace<CustomerPresenter> {
}
However after run, it does not show the Gui even I loggined. I tested & found that canReveal() in MyGateKeeper was called before PassUserInfoHandler() was called, so canReveal never return true;
How to fix this problem?
The usual pattern to accomplish this is to bind a CurrentUser class in Singleton:
bind(CurrentUser.class).in(Singleton.class);
and inject it into your GateKeeper. Inside your GateKeeper's canReveal method, you'll check that currentUser.isLoggedIn() :
private final CurrentUser currentUser;
#Inject
MyGateKeeper(CurrentUser currentUser) {
this.currentUser = currentUser;
}
#Override
public boolean canReveal() {
return currentUser.isLoggedIn();
}
You should initialize the CurrentUser.isLoggedIn field inside your Bootstrapper (see https://github.com/ArcBees/GWTP/wiki/Bootstrapping-or-Application-Initialization) by calling your server. Here's an example using GWTP's RestDispatch:
public class BootstrapperImpl implements Bootstrapper {
private final String unauthorizedPlace;
private final CurrentUser currentUser;
private final PlaceManager placeManager;
private final RestDispatch restDispatch;
private final UserResource userResource;
#Inject
BootstrapperImpl(
#UnauthorizedPlace String unauthorizedPlace,
CurrentUser currentUser,
PlaceManager placeManager,
RestDispatch restDispatch,
UserResource userResource) {
this.unauthorizedPlace = unauthorizedPlace;
this.currentUser = currentUser;
this.placeManager = placeManager;
this.restDispatch = restDispatch;
this.userResource = userResource;
}
#Override
public void onBootstrap() {
checkIfUserIsLoggedIn();
}
private void checkIfUserIsLoggedIn() {
restDispatch.execute(userResource.isCurrentUserLoggedIn(), new AbstractAsyncCallback<Boolean>() {
#Override
public void onSuccess(Boolean isCurrentUserLoggedIn) {
navigate(isCurrentUserLoggedIn);
}
});
}
private void navigate(Boolean isCurrentUserLoggedIn) {
currentUser.setLoggedIn(isCurrentUserLoggedIn);
if (isCurrentUserLoggedIn) {
placeManager.revealCurrentPlace();
} else {
placeManager.revealPlace(new PlaceRequest.Builder().nameToken(unauthorizedPlace).build());
}
}
}

Struts 2 ModelDriven Action suporting both a list and individual items

I have inherited some struts2 REST-plugin based code, and the following construct puzzles me:
#Namespace("/merchants/{id}")
public class MerchantAction extends ActionSupport implements ModelDriven<Object> {
private Merchant merchant = new Merchant(); // A Model
private Iterable<Merchant> merchants; // A list of models
....
public HttpHeaders index() {
merchants = merchantService.findAllMerchants();
return new DefaultHttpHeaders("index");
}
#Override
public Object getModel() {
return (merchant != null ? merchant : merchants);
}
public void setId(String id) {
merchant = merchantService.findMerchant(id));
}
In other words, it seems to be toggling between returning a list and returning an individual item in the getModel() call. Is this kosher ? Looks a bit strange to me
I've considered your approach, but finally gave it up. IMO, it lost the advantage of strong typed action.
My solution is, creating a ViewModel for each action. In the view models, there can be the single model, the list of the model, and other items for pages usage, such as items for drop down list or radio buttons.
So the UserViewModel is like:
public class UserViewModel implements IViewModel<User> {
private User model;
private List<User> list;
public void setModel(User user) {
this.model = user;
}
public User getModel() {
return model;
}
public void setList(List<User> list) {
this.list = list;
}
public List<User> getList() {
return list;
}
}
And the actions are like:
public class UserController implements ModelDriven<UserViewModel> {
private int id;
private UserViewModel model = new UserViewModel();
public String index() {
return "success";
}
public String show() {
return "success";
}
public void setId(int id) {
this.id = id;
}
public int getId() {
return this.id;
}
#Override
public UserViewModel getModel() {
return model;
}
}
But in this way, I still lose the shortcut way in jsp files. I should write long model.userName instead of short userName.
I'm still finding the best solution of it.

How to respond to URLs with GWT's built-in MVP-framework?

I'm building a very simple calendar app to get familiar with the MVP-framework introduced with the 2.1 version of GWT.
What I want to achieve is being able to switch between a list of scheduled appointments and a list of the avialable time.
I have created the a CalendarPlace, CalendarActivity, CalendarView and CalendarViewImpl.
I know that to navigate to a different place i would call PlaceController.goTo(Place), so in my calendar app I would call:
clientFactory.getPlaceController.goTo(new CalendarPlace("freeTime");
The URL would be index.html#CalendarPlace:freeTime for the list of free time or
clientFactory.getPlaceController.goTo(new CalendarPlace("appointments");
for the list of scheduled appointments. The URL would be index.html#CalendarPlace:appointments
But the question is where do I respond to the different tokens? I guess the CalendarPlace would be the right place, but how would I do that?
Here is my source code(I took most of the boilerplate from the tutorial here:
CalendarPlace:
public class CalendarPlace extends Place {
private String calendarName;
public CalendarPlace(String token) {
this.calendarName = token;
}
public String getCalendarName() {
return calendarName;
}
public static class Tokenizer implements PlaceTokenizer<CalendarPlace> {
#Override
public CalendarPlace getPlace(String token) {
return new CalendarPlace(token);
}
#Override
public String getToken(CalendarPlace place) {
return place.getCalendarName();
}
}
}
CalendarActivity:
public class CalendarActivity extends AbstractActivity
implements
CalendarView.Presenter {
private ClientFactory clientFactory;
private String name;
public CalendarActivity(CalendarPlace place, ClientFactory clientFactory) {
this.name = place.getCalendarName();
this.clientFactory = clientFactory;
}
#Override
public void goTo(Place place) {
clientFactory.getPlaceController().goTo(place);
}
#Override
public void start(AcceptsOneWidget containerWidget, EventBus eventBus) {
CalendarView calendarView = clientFactory.getCalendarView();
calendarView.setName(name);
calendarView.setPresenter(this);
containerWidget.setWidget(calendarView.asWidget());
}
}
CalendarViewImpl:
public class CalendarViewImpl extends Composite implements CalendarView {
private VerticalPanel content;
private String name;
private Presenter presenter;
private OptionBox optionBox;
public CalendarViewImpl() {
//optionBox is used for navigation
//optionBox is where I call PlaceController.goTo() from
optionBox=new OptionBox();
RootPanel.get("bluebar").add(optionBox);
content=new VerticalPanel();
this.initWidget(content);
}
#Override
public void setPresenter(Presenter listener) {
this.presenter=listener;
}
#Override
public void setName(String calendarName) {
this.name = calendarName;
}
public void displayFreeTime() {
//called from somewhere to display the free time
}
public void getAppointments() {
//called from somewhere to display the appointments
}
}
In your CalendarActivity constructor you have access to the place, and therefore the token. Tuck it aside, and then in your start() method you can use it. Activities are meant to be lightweight objects, created for each new navigation.