I am trying to save a user id to a new biz. I keep getting a 400 error and can not figure out why. I am using django for the backend with graphql and apollo client for the front with vue js. I am able to get the owner id but not able to save it for some reason.
Create Biz Mutation Apollo
export const CREATE_BIZ_MUTATION = gql`
mutation CreateBizMutation($name: String!, $owner: ID!) {
createBiz(name: $name, ownerId: $owner) {
name
}
}`
Create Biz mutation Django
class CreateBiz(graphene.Mutation):
id = graphene.Int()
name = graphene.String()
code = graphene.String()
owner = graphene.Field(UserType)
class Arguments:
name = graphene.String()
def mutate(self, info, name):
user = get_user(info) or None
code = ''.join(random.SystemRandom().choice(string.ascii_uppercase + string.digits + string.ascii_lowercase) for _ in range(6))
biz = Biz(
code = code,
name = name,
owner = user
)
biz.save()
return CreateBiz(
id= biz.id,
name = biz.name,
code = biz.code,
owner = biz.owner
)
Create Biz Component
createBiz () {
const owner = localStorage.getItem(DJANGO_USER_ID)
if (!owner) {
console.error('No user logged in')
return
}
const { name } = this.$data
this.$apollo.mutate({
mutation: CREATE_BIZ_MUTATION,
variables: {
name,
owner
}
}).catch((error) => {
console.log(error)
})
}
}
Related
I am using fetch on the frontend to send data to my flask backend in order to make a movie seat booking. The whole process works fine until the client awaits the response, which is "undefined" . So , basically the database saves the data , the only problem is the response which is sent to the client. I used jsonify which usually works fine. Can anybody tell me what I am missing? Thanks in advance.
Here is the JS code :
function sendReservationToServer() {
const selectedSeats = sessionStorage.getItem('selectedSeats')
const reservation = { userId, selectedSeats, showTimeId, movieHallId }
fetch('/bookSeats', {
method: 'post',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(reservation)
}).then(response => {
response.json()
}).then(data => {
theatreHall.innerHTML = `${data} <br> <a href='/home'>Back to main menu</a>`
console.log(`${data}`)
}).catch(err => infoMsg.textContent = err)
sessionStorage.clear()
}
And this is the flask controller which handles the request:
#app.route("/bookSeats", methods=["POST"])
def book_seats():
selected_seats = request.json
user_id = selected_seats.get('userId')
seats = json.loads(selected_seats.get('selectedSeats'))
movie_hall_id = selected_seats.get('movieHallId')
seat_ids = []
showtime_id = selected_seats.get('showTimeId')
for seat in seats:
seat_ids.append(db.session.query(Seat).filter(
Seat.seat_number == seat).filter(Seat.movie_hall_id == movie_hall_id).all()[0].stid)
for seat in seat_ids:
reserved_seat = ReservedSeat(
seat_id=seat, show_time=showtime_id, user=user_id)
db.session.add(reserved_seat)
db.session.commit()
reservation = Reservation(
user=user_id, show_time=showtime_id, number_of_tickets=len(seat_ids))
db.session.add(reservation)
db.session.commit()
message = f'{seats} booked successfully'
return jsonify(message)
data is undefined because the first then does not return anything. Either make it return response.json() or move everything in the second then to the first and replace data with response.json().
Hi guys i am on trouble about getting the current user provided by spring.
Here's my unit test code
void "Test if adding project will sucess"() {
given:
def createProjectMock = mockFor(UserService)
createProjectMock.demand.createNewProject { Map projectMap ->
return true
}
controller.userService = createProjectMock.createMock()
when: "saveProject is execute"
controller.saveProject()
then: "page will to the list to view the saved project"
response.redirectedUrl == '/user/index2'
}
Here's my controller
def saveProject(ProjectActionCommand projectCmd) {
def currentUser = springSecurityService.currentUser
if (projectCmd.hasErrors()) {
render view: 'createProject', model: [projectInstance: projectCmd, user:currentUser]
} else {
def getProjectMap = [:]
getProjectMap = [
projectName: params.projectName,
user: currentUser
]
def saveProject = userService.createNewProject(getProjectMap)
if (saveProject) {
redirect view: 'index2'
} else {
render 'Error upon saving'
}
}
}
And here's my service
Project createNewProject(Map projectMap){
def createProject = new Project()
createProject.with {
projectName = projectMap.projectName
user = projectMap.user
}
createProject.save(failOnError:true, flush: true)
}
And i always getting this error:
Cannot get property 'currentUser' on null object.
Hope you can help me. Thanks
Cannot get property 'currentUser' on null object.
means that you haven't mocked springSecurityService. Let's do it in setup section (I assume it may be useful also in other methods in this class):
def springSecurityService
def setup() {
springSecurityService = Mock(SpringSecurityService)
controller.springSecurityService = springSecurityService
}
At this point your code is going to work. However remember that you can always mock also the actual logged user and test it at any point:
User user = Mock(User)
springSecurityService.currentUser >> user
I developed an Angular application where the user can handle brands.
When creating/updating a brand, the user can also upload a logo. All data are sent to the DB via a REST API built using the Django REST Framework.
Using the Django REST Framework API website I'm able to upload files, but using Angular when I send data thu the API I get an error.
I also tried to encode the File object to base64 using FileReader, but I get the same error from Django.
Can you help me understanding the issue?
Models:
export class Brand {
id: number;
name: string;
description: string;
is_active: boolean = true;
is_customer_brand: boolean = false;
logo_img: Image;
}
export class Image {
id: number;
img: string; // URL path to the image (full size)
img_md: string; // medium size
img_sm: string; // small
img_xs: string; // extra-small/thumbnail
}
Service:
import { Injectable } from '#angular/core';
import { Http, Response } from '#angular/http';
import { Headers, RequestOptions } from '#angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import { Brand } from './brand';
const endpoint = 'http://127.0.0.1:8000/api/brands/'
#Injectable()
export class BrandService {
private brands: Array<Brand>;
constructor(private http: Http) { }
list(): Observable<Array<Brand>> {
return this.http.get(endpoint)
.map(response => {
this.brands = response.json() as Brand[];
return response.json();
})
.catch(this.handleError);
}
create(brand: Brand): Observable<Brand> {
console.log(brand);
return this.http.post(endpoint+'create/', brand)
.map(response => response.json())
.catch(this.handleError);
}
get(id): Observable<Brand> {
return this.http.get(endpoint+id)
.map(response => response.json())
.catch(this.handleError);
}
private handleError(error:any, caught:any): any {
console.log(error, caught);
}
}
Error from the browser console:
"{"logo_img":{"img":["The submitted data was not a file. Check the
encoding type on the form."]}}"
Django Serializer:
class BrandSerializer(ModelSerializer):
is_active = BooleanField(required=False)
logo_img = ImageSerializer(required=False, allow_null=True)
class Meta:
model = Brand
fields = [
'id',
'name',
'description',
'is_active',
'is_customer_brand',
'logo_img',
]
def update(self, instance, validated_data):
image = validated_data.get('logo_img',None)
old_image = None
if image:
image = image.get('img',None)
brand_str = validated_data['name'].lower().replace(' ','-')
ext = validated_data['logo_img']['img'].name.split('.')[-1].lower()
filename = '{0}.{1}'.format(brand_str,ext)
user = None
request = self.context.get('request')
if request and hasattr(request, 'user'):
user = request.user
image_serializer_class = create_image_serializer(path='logos', filename=filename, created_by=user, img_config = {'max_w':3000.0,'max_h':3000.0,'max_file_size':1.5,'to_jpeg':False})
image_serializer = image_serializer_class(data=validated_data['logo_img'])
image_serializer.is_valid()
validated_data['logo_img'] = image_serializer.save()
old_image = instance.logo_img
super(BrandSerializer, self).update(instance,validated_data)
if old_image: # Removing old logo
old_image.img.delete()
old_image.img_md.delete()
old_image.img_sm.delete()
old_image.img_xs.delete()
old_image.delete()
return instance
def create(self, validated_data):
image = validated_data.get('logo_img',None)
print(image)
if image:
print(image)
image = image.get('img',None)
print(image)
brand_str = validated_data['name'].lower().replace(' ','-')
ext = validated_data['logo_img']['img'].name.split('.')[-1].lower()
filename = '{0}.{1}'.format(brand_str,ext)
user = None
request = self.context.get('request')
if request and hasattr(request, 'user'):
user = request.user
image_serializer_class = create_image_serializer(path='logos', filename=filename, created_by=user, img_config = {'max_w':3000.0,'max_h':3000.0,'max_file_size':1.5,'to_jpeg':False})
image_serializer = image_serializer_class(data=validated_data['logo_img'])
image_serializer.is_valid()
validated_data['logo_img'] = image_serializer.save()
return super(BrandSerializer, self).create(validated_data)
When posting a new brand to the server with files, I have three main choices:
Base64 encode the file, at the expense of increasing the data size by around 33%.
Send the file first in a multipart/form-data POST, and return an ID to the client. The client then sends the metadata with the ID, and the server re-associates the file and the metadata.
Send the metadata first, and return an ID to the client. The client then sends the file with the ID, and the server re-associates the file and the metadata.
The Base64 encoding will involve unacceptable payload.
So I choose to use multipart/form-data.
Here's how I implemented it in Angular's service:
create(brand: Brand): Observable<Brand> {
let headers = new Headers();
let formData = new FormData(); // Note: FormData values can only be string or File/Blob objects
Object.entries(brand).forEach(([key, value]) => {
if (key === 'logo_img') {
formData.append('logo_img_file', value.img);
} else {
formData.append(key, value);
});
return this.http.post(endpoint+'create/', formData)
.map(response => response.json())
.catch(this.handleError);
}
IMPORTANT NOTE: Since there's no way to have nested fields using FormData, I cannot append formData.append('logo_img', {'img' : FILE_OBJ }). I had change the API in order to receive the file in one field called logo_img_file.
Hope that my issue helped someone.
I am trying to test for failure conditions of my Account controller. When i run the test in debug mode, i am not seeing an expected result. I am expecting to return a failed identity result when reach the line of code to create a user async. however, in debug mode, it does not contain the error i provide it, and the success property is true. according to this site: https://www.symbolsource.org/MyGet/Metadata/aspnetwebstacknightly/Project/Microsoft.AspNet.Identity.Core/2.0.0-rtm-140226/Release/Default/Microsoft.AspNet.Identity.Core/Microsoft.AspNet.Identity.Core/IdentityResult.cs?ImageName=Microsoft.AspNet.Identity.Core, the way i am going about this it "should" work.
what is the right way to setup this test so that when i hit UserManager.CreateAsync, it will return a Failed IdentityResult?
Test i am trying to run
[TestMethod]
public async Task AccountController_Post_register_valid_model_account_creation_fails_returns_exception_result()
{
// arrange
RegisterApiModel model = new RegisterApiModel
{
BusinessType = BusinessType.Architect,
City = "asdf",
CompanyName = "asdf",
Email = "asdf#asdf.com",
FirstName = "asdf",
JobTitle = "asdf",
LastName = "asdf",
OperatingDistance = 123,
Phone = "1231231234",
Password = "12345678",
PostalCode = "asdf",
PrimaryContactName = "asdf",
PrimaryContactPhone = "1231231234",
PrimaryContactTitle = "asdf",
StateId = 2
};
// create http request
var config = new HttpConfiguration();
var request = new HttpRequestMessage(HttpMethod.Post, "http://localhost.com/api/Account/Register");
var route = config.Routes.MapHttpRoute("DefaultApi", "api/{controller}/{id}");
var routeData = new HttpRouteData(route, new HttpRouteValueDictionary { { "controller", "Companies" } });
// mock userstore
Mock<IUserStore<ApplicationUser>> userStore = new Mock<IUserStore<ApplicationUser>>();
userStore.Setup(x => x.CreateAsync(It.IsAny<ApplicationUser>())).Returns(Task.FromResult(IdentityResult.Failed("Name " + model.Email + " already exists")));
var passwordManager = userStore.As<IUserPasswordStore<ApplicationUser>>();
ApplicationUserManager um = new ApplicationUserManager(userStore.Object);
um.PasswordValidator = pwValidator;
AccountController controller = new AccountController(um);
controller.ControllerContext = new HttpControllerContext(config, routeData, request);
controller.Request = request;
controller.Request.Properties[HttpPropertyKeys.HttpConfigurationKey] = config;
// act
var result = await controller.Register(model);
// assert
result.ShouldBeType(typeof(ExceptionResult));
}
web api method i am trying to test
public async Task<IHttpActionResult> Register([FromBody]RegisterApiModel model)
{
try
{
var company = new Company
{
Name = model.CompanyName,
CreateDate = DateTime.Now,
SubscriptionStatus = SubscriptionStatus.Free,
Address1 = model.Address1 ?? string.Empty,
Address2 = model.Address2 ?? string.Empty,
City = model.City,
StateId = model.StateId,
PostalCode = model.PostalCode,
BusinessType = model.BusinessType.Value,
OperatingDistance = model.OperatingDistance.Value,
Phone = PhoneNumber.ToStorage(model.Phone),
Fax = model.Fax == null ? string.Empty : PhoneNumber.ToStorage(model.Fax),
PrimaryContactName = model.PrimaryContactName,
PrimaryContactPhone = PhoneNumber.ToStorage(model.PrimaryContactPhone),
PrimaryContactTitle = model.PrimaryContactTitle
};
var user = new ApplicationUser { UserName = model.Email, Email = model.Email, FirstName = model.FirstName, LastName = model.LastName, Company = company, JobTitle = model.JobTitle };
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
// make user a company admin
user.Claims.Add(new Microsoft.AspNet.Identity.EntityFramework.IdentityUserClaim { ClaimValue = "Admin", ClaimType = "http://bidchuck.com/company/role", UserId = user.Id });
result = await UserManager.UpdateAsync(user);
if (result.Succeeded)
{
var code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
var callbackUrl = Url.Link("Default", new { controller = "Account", action = "ConfirmEmail", userId = user.Id, code = code });
await UserManager.SendEmailAsync(user.Id, "Confirm your account", "Please confirm your account by clicking this link: link");
return Ok();
}
}
return BadRequest(result.Errors.First());
}
catch (Exception ex)
{
return InternalServerError(ex);
}
}
First of all, you are looking on source of Identity 2.2-alpha1 - it is not released yet. Better get decompiler (I use DotPeek from Jetbrains) and decompile assemblies you use in your project.
Then you are trying to test on too high level. Extract your method into class that is independent from your controllers:
UserService
{
public IdentityResult CreateUser(RegisterApiModel model, String urlCallback)
{
// don't forget to add generated code and userId as parameters into url
// do your user creation.
}
}
In your controller call this service:
public async Task<IHttpActionResult> Register([FromBody]RegisterApiModel model)
{
var urlCallbac = Url.Link("Default", new { controller = "Account", action = "ConfirmEmail" });
var result = await userService.CreateUserAsync(model, urlCallback);
if (result.Succeeded)
{
return Ok();
}
return BadRequest(result.Errors.First());
}
And test user Service separately from controllers. Your tests will become much more simple.
And at the moment it is very difficult to say why you are getting this result. Probably mocks are not completely set up to do what's needed to be done.
I'm writing controller unit tests and I'd like to test json result when creation fails.
How can I register VndErrorJsonRenderer in unit test ? I tried simply defineBeans in setup() but it doesn't work :(
import com.vividsolutions.jts.geom.Coordinate
import grails.transaction.Transactional
import org.codehaus.groovy.grails.web.servlet.mvc.GrailsParameterMap
import static org.springframework.http.HttpStatus.CREATED
import static org.springframework.http.HttpStatus.NO_CONTENT
#Transactional(readOnly = true)
class UserController {
static namespace = "v1"
static allowedMethods = [profile: 'GET', create: "POST", update: "PUT", delete: "DELETE"]
static responseFormats = ['json', 'vnd.error+json']
def springSecurityService
def geometryFactory
/**
* Saves a resource
*/
#Transactional
def create() {
User instance = createResource(params)
instance.validate()
if (instance.hasErrors()) {
respond instance.errors, view: 'create' // STATUS CODE 422
return
}
instance.save flush: true
respond instance, [status: CREATED]
}
protected User createResource(GrailsParameterMap params) {
Double x = params.double("location.x", 0)
Double y = params.double("location.y", 0)
User user = new User()
bindData(user, params, [include: ['username', 'password', 'profile.*']])
if (x > 0 && y > 0)
user.location = geometryFactory.createPoint(new Coordinate(x, y))
else
user.location = null
user.roles = []
user.roles.add(Role.findByAuthority(Role.ROLE_USER))
return user
}
}
And my test :
#Before
void setup() {
defineBeans {
vndJsonErrorRenderer(VndErrorJsonRenderer)
}
}
void "Test the create action with a non unique username"() {
User.metaClass.encodePassword = {
"aaa"
}
// Create first user
assertNotNull getValidUser().save(flush: true)
when: "The create action is executed with a username already used"
def user = getValidUser()
controller.request.addHeader("Accept", "application/vnd.error+json,application/json")
controller.request.contentType = "application/json"
controller.request.content = JsonMapperUtil.mapAsJson(user)?.getBytes()
controller.create()
then: "The response status is UNPROCESSABLE_ENTITY and the username unique error is returned"
println response.text
response.status == UNPROCESSABLE_ENTITY.value
def json = JSON.parse(response.text)
assertNull "VND format not returned", json.errors
}
I'm using grails 2.3.6 with restful controller.
Thanks
In the case you are showing where you depend on respond it would be best to test this more as an integration test so all components that may interact with respond are all wired for you.
In a unit test for what ever beans are needed in the class under test I find it easiest to directly set them on the class under test.