garethbjohnson / gutendex

Web API for Project Gutenberg ebook metadata
https://gutendex.com
MIT License
231 stars 46 forks source link

user registration & authentication #7

Closed pmburu closed 4 years ago

pmburu commented 5 years ago

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.

garethbjohnson commented 5 years ago

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. 🙂

pmburu commented 5 years ago

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

garethbjohnson commented 5 years ago

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. 🙂

pmburu commented 5 years ago

`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

garethbjohnson commented 5 years ago

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.

pmburu commented 4 years ago

Hello Johnson,

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

garethbjohnson commented 4 years ago

Hi Peter, would you like anymore help with this?

pmburu commented 4 years ago

Hi Gareth,

Yes I would like some more guidance on this. Also I would like to talk to you about more projects and ideas as I seek guidance and mentorship.

Kind Regards, Peter Mburu

On Thu, 30 Jan 2020 at 13:22, Gareth Johnson notifications@github.com wrote:

Hi Peter, would you like anymore help with this?

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/garethbjohnson/gutendex/issues/7?email_source=notifications&email_token=ABR7SS46NVQRJLJBAEUMHVTRAKS7XA5CNFSM4JI3B54KYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEKKO7RQ#issuecomment-580186054, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABR7SS7BXJIMTZOQQP352ATRAKS7XANCNFSM4JI3B54A .

garethbjohnson commented 4 years ago

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