Skip to content
This repository has been archived by the owner on Jul 17, 2020. It is now read-only.

Getting the community scope #22

Open
luap42 opened this issue Jan 18, 2020 · 15 comments
Open

Getting the community scope #22

luap42 opened this issue Jan 18, 2020 · 15 comments
Labels
area: backend Changes to server-side code meta: help wanted Extra attention is needed type: change request New feature, request, or behaviour change

Comments

@luap42
Copy link
Member

luap42 commented Jan 18, 2020

I think we need to have this before being able to work on posts and users:

https://github.com/codidact/core/projects/1#card-31579420

A system, which parses the URL, gets the community ID from it, verifies, whether that is in the DB and if it is, loads some information (name, tagline) into memory and passes that to the further controllers and views.

I'd do it, but I don't have enough knowledge in ASP.NET Core, so I'd like to ask for volunteers doing it. :)

Please reply here, when you can do this and I'll assign this task to you.

@luap42 luap42 added area: backend Changes to server-side code meta: help wanted Extra attention is needed labels Jan 18, 2020
@benjamin-allen
Copy link
Contributor

I can take a stab at it. Are you envisioning this code running before every controller?

@misha130
Copy link
Contributor

#21 is blocking this

@luap42
Copy link
Member Author

luap42 commented Jan 18, 2020

Most. There'll be some "neutral" pages, such as authentication, administration and community management (add, edit, remove), though.

@benjamin-allen
Copy link
Contributor

Most. There'll be some "neutral" pages, such as authentication, administration and community management (add, edit, remove), though.

That should be possible. I'll make a base controller class that performs the URL parsing you describe. Controllers that don't want that functionality just don't inherit from that base class.

#21 is blocking this

I'm not sure why that's the case. The way I'm reading it is that this issue relates to only community data and that issue is concerned with user auth. Am I missing something?

@misha130
Copy link
Contributor

misha130 commented Jan 18, 2020

I'm not sure why that's the case. The way I'm reading it is that this issue relates to only community data and that issue is concerned with user auth. Am I missing something?

I misread the issue at hand.
I think we are talking about only displaying in part of a page the community tagline and name.
Just need to create a PartialView/View for this task that checks the URL and displays the community based on that. You don't need to create base controllers or anything like that.

@asynts
Copy link
Contributor

asynts commented Jan 19, 2020

If my understanding is correct, then the consensus was to use subdomains. This would require a bit more configuration that is currently documented in README.md.

IIS Express (that is the server thingy that Visual Studio uses) only binds to e.g. https://localhost:8080 by default, but not to e.g. https://foo.localhost:8080. Thus to develop and test this service scope middleware or whatever, a more sophisticated setup is required.

I've tried to come up with something myself, and found this stack overflow answer which seemed promising, but didn't work for me.

Does anyone know how to configure this on Windows?


I've managed to set this up on Linux as follows:

  1. Edit /etc/hosts and add:

    127.0.0.2    codidact.local
    127.0.0.2    foo.codidact.local
    127.0.0.2    bar.codidact.local
    
  2. Edit src/WebUI/Properties/launchSettings.json as follows:

    {
      "profiles": {
        "WebUI": {
          "commandName": "Project",
          "launchBrowser": true,
          "applicationUrl": "https://codidact.local",
          "environmentVariables": {
            "ASPNETCORE_ENVIRONMENT": "Development"
          }
        }
      }
    }

@manassehkatz
Copy link

My recommendation (I think I made it clear in the forum) is that the Codidact software should support both methods, while the Codidact primary instance should (normally, see exception) use subdomains:

  • Use DNS + extra certificates (because Let's Encrypt doesn't do wildcard subdomains and Let's Encrypt is the only practical certificate at this point in time for a low-budget operation - others cost a lot (relatively speaking) and self-signed is no longer a practical option due to browser warnings), etc. to support subdomains.
  • Add a "glue" piece somewhere (middleware or whatever) that maps a.example.com to example.com/community/a (where example.com is the primary instance domain - e.g., codidact.com) and community is an instance-configurable pseudo-directory name (also called 'X' in one of the prior discussions). Technically speaking 'a.' and '/a' could have different values, but easiest (for a few reasons) to require them to be the same - e.g., writing.codidact.com and codidact.com/community/writing)
  • The application software only very minimally needs to even know about the existence of the subdomain setting. Essentially, it has a few configuration items:
    • instance domain - e.g., codidact.com
    • community separator - e.g., community or site or X (note, this is needed to avoid naming conflicts with instance-level URLs - e.g., otherwise if you had a site for SysAdmins and called it "admin" then codidact.com/admin would be ambiguous for "admin" community vs. "admin" page for the instance.
    • per-community: community identifier (limited to valid domain name alphanumeric/etc.) - e.g., writing, diy, judaism, rc, etc.)
    • per-community: use_subdomain - This is necessary because even a Codidact instance that mostly uses subdomains may need this. For example, when setting up a new community, this allows the setup to be done prior to setting up DNS for the new subdomain. If an instance has an Area 51, there might a rule (policy only, not technical) to only set up a subdomain once a community has reached a certain stage (Beta?). etc.

The code should care very little about this. It effectively becomes a "filter" of sorts on input and output - like Apache RewriteRule, except managed to a certain degree (I know it can be done, just not exactly how) within the software.

@ranolfi
Copy link
Member

ranolfi commented Jan 21, 2020

Do we really need to implement anything at the application level to manage this? AFAIK it's usually done at the server level (URL Rewrite in Apache, IIS or whatever else).

It wasn't long ago that I refactored out some old URL rewriting code from a legacy .NET web application and ported all rules to IIS instead. Worked just as well, if not better. Very nice to maintain and everyone was happy.

@asynts
Copy link
Contributor

asynts commented Jan 21, 2020

Do we really need to implement anything at the application level to manage this? AFAIK it's usually done at the server level (URL Rewrite in Apache, IIS or whatever else).

The rewriting should only happen if some configuration option is turned on.

If we put this option into the server configuration, it might be necessary to get that information in the application too for e.g. redirects. This would mean redundancy or some common configuration file which seems difficult.


I am also unsure how much the server configuration has to offer, there is also a URL Rewriting Middleware in ASP.NET integrated, but it's not powerful enough to do this rewriting (at least to my knowledge).

@ranolfi
Copy link
Member

ranolfi commented Jan 21, 2020

The rewriting should only happen if some configuration option is turned on.

Is this requirement specified somewhere? I must have missed it (and, in principle, don't agree with).

If we put this option into the server configuration, it might be necessary to get that information in the application too for e.g. redirects. This would mean redundancy or some common configuration file which seems difficult.

In terms of KISS, I very much doubt it will be more difficult than implementing and specially maintaining the middleware in the long term.

I am also unsure how much the server configuration has to offer

A lot! More than enough for the current needs (that I'm aware of).

I maintain that the server configuration is the right place to do this. When there is a requirement for localizing URLs, a middleware might be considered for that specific purpose.

@asynts
Copy link
Contributor

asynts commented Jan 21, 2020

Your formatting is broken, you have to put a newline after a quote, otherwise it is lazily continued.

Is this requirement specified somewhere? I must have missed it (and, in principle, don't agree with).

There was some discussion here, and some stuff further down the thread, leading to this post.

The big plus is that we can use subdomains on https://codidact.com while allowing other instances to use the path schema.

A lot! More than enough for the current needs (that I'm aware of).

I've never done rewriting in a server configuration, maybe one simple regex but nothing more. Maybe someone could provide an example of how this could be done. I got the suspicion that this results in one mega regex that is completely unreadable.

@ranolfi
Copy link
Member

ranolfi commented Jan 21, 2020

Your formatting is broken, you have to put a newline after a quote, otherwise it is lazily continued.

Got it, ty.

Let me follow up on those and come back later to comment. :)

@asynts
Copy link
Contributor

asynts commented Jan 22, 2020

@ranolfi I changed my position on this topic. Don't get me wrong, on the long term doing it with configuration options in C# would is preferable in my opinion, however, we are creating a minimum viable product, thus simpler is better.

I've come up with the following configuration for Nginx:

events {
}

http {
    server {
        listen 80;
        server_name localhost;

        location / {
            proxy_pass https://127.1.0.1:8080/;
        }
    }

    server {
        listen 80;
        server_name ~^(?<community>\w+)\.localhost$;

        location / {
            proxy_pass https://127.1.0.1:8080/community/$community$uri;
        }
    }
}

I am sure something similar can be done in IIS too, but I think someone with Windows knowledge should address that. This can also be done at a later date, because we'd use the path schema during development anyway.

I'll close #23 and salvage some of the configuration stuff in a separate pull request, unless anyone objects.

@asynts
Copy link
Contributor

asynts commented Jan 22, 2020

I edited the configuration to use encryption and added the redirect:

events {
}

http {
    ssl_certificate certs/cert.pem;
    ssl_certificate_key certs/key.pem;

    server {
        listen 443 ssl;
        server_name localhost;

        location ~^/community/(?<community>\w+)(?<path>.*?)$ {
            return 301 https://$community.localhost$path;
        }

        location / {
            proxy_pass https://127.1.0.1:8080/;
        }
    }

    server {
        listen 443 ssl;
        server_name ~^(?<community>\w+)\.localhost$;

        location / {
            proxy_pass https://127.1.0.1:8080/community/$community$request_uri;
        }
    }
}

@misha130
Copy link
Contributor

For anyone that wants to actually do it here is what you need to do:

! PSUEDO CODE WARNING !
Add a routing option in the startup, example:

       app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "/community/{community}/{controller}/{action}/{id?}");
            });

Add the global filter if appropriate:

                    var routerData  = ....
                    var isCommunityable= entity.FindProperty(nameof(ICommunityable.CommunityId));
                    var parameter = Expression.Parameter(entity.ClrType, "p");
                    var equalExpression = Expression.Equal(
                            Expression.Property(parameter, isCommunityable.PropertyInfo),
                            Expression.Constant(routerData["Community"])
                        );
                    var filter = Expression.Lambda(equalExpression, parameter);
                    entity.SetQueryFilter(filter);

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area: backend Changes to server-side code meta: help wanted Extra attention is needed type: change request New feature, request, or behaviour change
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants