garethbjohnson/gutendex

user registration & authentication

Closed this issue ยท 9 comments

Hello Gareth,

First of all thank you for providing this API to open source. I have learnt alot through perusing and manipulating some code.

I wanted to know how to register and authenticate users who then get access to particular books. I would like to register users with - username, firstname, lastname, email and passwords. I can provide the code base of what I have done.

Kindly help.

Hello Peter, that seems fairly difficult! If you want to use Django, though, I think I can help. Feel free to send me your code, and then I can try to give you some advice when I have some free time. ๐Ÿ™‚

Thank you Gareth for getting back.

See below the code. I have changes on the models, views, urls and settings
https://github.com/pmburu/LibOpenDataApi

I recommend adding a relationship between the user and books models. I see you already have a CustomUser model, so I think adding this line to your CustomerUser model would work:

    books = models.ManyToManyField('Book')

Then, after you run python manage.py makemigrations and python manage.py migrate, you will have a connection between User and Book through CustomUser. You can then add books to each user, such as through the Django shell, admin site, or some website feature you build.

After that, you can return only the right books from BookViewSet. You can do that by replacing the first line of BookViewSet.get_queryset with this:

        if self.request.user.is_authenticated and hasattr(self.request.user, 'customuser'):
            return

        queryset = self.request.user.customuser.books
        queryset = queryset.order_by('-download_count')
        queryset = queryset.exclude(download_count__isnull=True)

This will only work if the user has a CustomUser, though. You can create one for each new user in RegisterUsersView.post by adding this line before return Response():

        CustomUser.objects.create(user=new_user, first_name=first_name, last_name=last_name)

If you want signup and login forms, you can add something like this to gutendex/templates/home.html:

{% if request.user.is_authenticated %}
    <h1>Welcome, {{ request.user }}!</h1>
{% else %}
    <form id="register-form">
        <h2>Register</h2>
        <input id="register-form-username" placeholder="Username">
        <input id="register-form-firstname" placeholder="First name">
        <input id="register-form-lastname" placeholder="Last name">
        <input id="register-form-email" placeholder="Email address">
        <input id="register-form-password" placeholder="Password" type="password">
        <button type=="submit">Register</button>
    </form>

    <script>
        const registerForm = document.getElementById('register-form')

        registerForm.addEventListener('submit', async event => {
            event.preventDefault()
            
            try {
                const response = await fetch('/auth/register/', {
                    body: JSON.stringify([
                        'username',
                        'firstname',
                        'lastname',
                        'email',
                        'password'
                    ].reduce((object, field) => ({
                        ...object,
                        [field]: document.getElementById(`register-form-${field}`).value
                    }), {})),
                    headers: {
                        'Content-Type': 'application/json'
                    },
                    method: 'POST'
                })
                
                if (response.status < 200 || response.status >= 300)
                    throw new Error('Invalid data')

                alert('Success! Please log in.')
                location.reload()
            } catch (error) {
                alert(error)
                return false
            }
        })
    </script>

    <form id="login-form">
        <h2>Log in</h2>
        <input id="login-form-username" placeholder="Username">
        <input id="login-form-password" placeholder="Password" type="password">
        <button type=="submit">Log in</button>
    </form>

    <script>
        const loginForm = document.getElementById('login-form')

        loginForm.addEventListener('submit', async event => {
            event.preventDefault()
            
            try {
                const response = await fetch('/auth/login/', {
                    body: JSON.stringify([
                        'username',
                        'password'
                    ].reduce((object, field) => ({
                        ...object,
                        [field]: document.getElementById(`login-form-${field}`).value
                    }), {})),
                    headers: {
                        'Content-Type': 'application/json'
                    },
                    method: 'POST'
                })
                
                if (response.status < 200 || response.status >= 300)
                    throw new Error('Invalid username or password')

                location.reload()
            } catch (error) {
                alert(error)
                return false
            }
        })
    </script>
{% endif %}

Let me know if this helps or if you have any questions. ๐Ÿ™‚

`if self.request.user.is_authenticated and hasattr(self.request.user, 'customuser'):
return

    queryset = self.request.user.customuser.books
    queryset = queryset.order_by('-download_count')
    queryset = queryset.exclude(download_count__isnull=True)`

I discovered that there is a bug here: The return screams syntax error

I do not see the syntax error. The code seems to work on my machine. If you post the full error message, I expect I will be able to help.

Hello Johnson,

Thank you for replying. I will get back asap with the error. I hope I will have solved it before.

Hi Peter, would you like anymore help with this?

Hi Peter, I will send you an email from my garethjohnson.io address about this since it outside bug reports or feature requests. ๐Ÿ‘