diff --git a/Makefile b/Makefile index ed8a6b8..7838040 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ GOFMT_FILES?=$$(find . -name '*.go' |grep -v vendor) GOFMT ?= gofmt -s -VERSION = 0.3.0 +VERSION = 0.4.0 test: fmt-check go test -i $(TEST) || exit 1 diff --git a/docs/resources/user.md b/docs/resources/user.md new file mode 100644 index 0000000..a992c95 --- /dev/null +++ b/docs/resources/user.md @@ -0,0 +1,60 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "gitea_user Resource - terraform-provider-gitea" +subcategory: "" +description: |- + gitea_user manages a native gitea user. + If you are using OIDC or other kinds of authentication mechanisms you can still try to managessh keys or other ressources this way +--- + +# gitea_user (Resource) + +`gitea_user` manages a native gitea user. + +If you are using OIDC or other kinds of authentication mechanisms you can still try to managessh keys or other ressources this way + +## Example Usage + +```terraform +resource "gitea_user" "test" { + username = "test" + login_name = "test" + password = "Geheim1!" + email = "test@user.dev" + must_change_password = false +} +``` + + +## Schema + +### Required + +- `email` (String) E-Mail Address of the user +- `login_name` (String) The login name can differ from the username +- `password` (String, Sensitive) Password to be set for the user +- `username` (String) Username of the user to be created + +### Optional + +- `active` (Boolean) Flag if this user should be active or not +- `admin` (Boolean) Flag if this user should be an administrator or not +- `allow_create_organization` (Boolean) +- `allow_git_hook` (Boolean) +- `allow_import_local` (Boolean) +- `description` (String) A description of the user +- `force_password_change` (Boolean) Flag if the user defined password should be overwritten or not +- `full_name` (String) Full name of the user +- `location` (String) +- `max_repo_creation` (Number) +- `must_change_password` (Boolean) Flag if the user should change the password after first login +- `prohibit_login` (Boolean) Flag if the user should not be allowed to log in (bot user) +- `restricted` (Boolean) +- `send_notification` (Boolean) Flag to send a notification about the user creation to the defined `email` +- `visibility` (String) Visibility of the user. Can be `public`, `limited` or `private` + +### Read-Only + +- `id` (String) The ID of this resource. + + diff --git a/examples/main.tf b/examples/main.tf index 194241b..6712d8a 100644 --- a/examples/main.tf +++ b/examples/main.tf @@ -23,5 +23,18 @@ resource "gitea_org" "test_org" { resource "gitea_repository" "org_repo" { username = gitea_org.test_org.name - name = "org-test-repo" -} \ No newline at end of file + name = "org-test-repo" +} + +data "gitea_user" "me" { + username = "lerentis" +} + +resource "gitea_user" "test" { + username = "test" + login_name = "test" + password = "Geheim1!" + email = "test@user.dev" + must_change_password = false + admin = true +} diff --git a/examples/provider.tf b/examples/provider.tf new file mode 100644 index 0000000..cd5336b --- /dev/null +++ b/examples/provider.tf @@ -0,0 +1,13 @@ +terraform { + required_providers { + gitea = { + source = "terraform.local/lerentis/gitea" + version = "0.4.0" + } + } +} + +provider "gitea" { + base_url = var.gitea_url + token = var.gitea_token +} \ No newline at end of file diff --git a/examples/resources/gitea_user/resource.tf b/examples/resources/gitea_user/resource.tf new file mode 100644 index 0000000..1b97b0f --- /dev/null +++ b/examples/resources/gitea_user/resource.tf @@ -0,0 +1,7 @@ +resource "gitea_user" "test" { + username = "test" + login_name = "test" + password = "Geheim1!" + email = "test@user.dev" + must_change_password = false +} \ No newline at end of file diff --git a/gitea/provider.go b/gitea/provider.go index e99b044..bc00644 100644 --- a/gitea/provider.go +++ b/gitea/provider.go @@ -76,7 +76,7 @@ func Provider() terraform.ResourceProvider { "gitea_org": resourceGiteaOrg(), // "gitea_team": resourceGiteaTeam(), // "gitea_repo": resourceGiteaRepo(), - // "gitea_user": resourceGiteaUser(), + "gitea_user": resourceGiteaUser(), "gitea_oauth2_app": resourceGiteaOauthApp(), "gitea_repository": resourceGiteaRepository(), }, diff --git a/gitea/resource_gitea_organisation.go b/gitea/resource_gitea_organisation.go index ba05df0..be78e41 100644 --- a/gitea/resource_gitea_organisation.go +++ b/gitea/resource_gitea_organisation.go @@ -17,8 +17,6 @@ const ( RepoAdminChangeTeamAccess string = "repo_admin_change_team_access" ) -type VisibleType string - func resourceOrgRead(d *schema.ResourceData, meta interface{}) (err error) { client := meta.(*gitea.Client) @@ -97,7 +95,7 @@ func resourceOrgUpdate(d *schema.ResourceData, meta interface{}) (err error) { return } -func respurceOrgDelete(d *schema.ResourceData, meta interface{}) (err error) { +func resourceOrgDelete(d *schema.ResourceData, meta interface{}) (err error) { client := meta.(*gitea.Client) var resp *gitea.Response @@ -133,7 +131,7 @@ func resourceGiteaOrg() *schema.Resource { Read: resourceOrgRead, Create: resourceOrgCreate, Update: resourceOrgUpdate, - Delete: respurceOrgDelete, + Delete: resourceOrgDelete, Importer: &schema.ResourceImporter{ State: schema.ImportStatePassthrough, }, diff --git a/gitea/resource_gitea_user.go b/gitea/resource_gitea_user.go new file mode 100644 index 0000000..8d05e47 --- /dev/null +++ b/gitea/resource_gitea_user.go @@ -0,0 +1,365 @@ +package gitea + +import ( + "fmt" + "strconv" + + "code.gitea.io/sdk/gitea" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" +) + +const ( + userName string = "username" + userLoginName string = "login_name" + userEmail string = "email" + userFullName string = "full_name" + userPassword string = "password" + userMustChangePassword string = "must_change_password" + userSendNotification string = "send_notification" + userVisibility string = "visibility" + userDescription string = "description" + userLocation string = "location" + userActive string = "active" + userAdmin string = "admin" + userAllowGitHook string = "allow_git_hook" + userAllowLocalImport string = "allow_import_local" + userMaxRepoCreation string = "max_repo_creation" + userPhorbitLogin string = "prohibit_login" + userAllowCreateOrgs string = "allow_create_organization" + userRestricted string = "restricted" + userForcePasswordChange string = "force_password_change" +) + +func resourceUserRead(d *schema.ResourceData, meta interface{}) (err error) { + client := meta.(*gitea.Client) + + id, err := strconv.ParseInt(d.Id(), 10, 64) + + var resp *gitea.Response + var user *gitea.User + + user, resp, err = client.GetUserByID(id) + + if err != nil { + if resp.StatusCode == 404 { + d.SetId("") + return nil + } else { + return err + } + } + + err = setUserResourceData(user, d) + + return +} + +func resourceUserCreate(d *schema.ResourceData, meta interface{}) (err error) { + client := meta.(*gitea.Client) + + var user *gitea.User + visibility := gitea.VisibleType(d.Get(userVisibility).(string)) + changePassword := d.Get(userMustChangePassword).(bool) + + opts := gitea.CreateUserOption{ + SourceID: 0, + LoginName: d.Get(userLoginName).(string), + Username: d.Get(userName).(string), + FullName: d.Get(userFullName).(string), + Email: d.Get(userEmail).(string), + Password: d.Get(userPassword).(string), + MustChangePassword: &changePassword, + SendNotify: d.Get(userSendNotification).(bool), + Visibility: &visibility, + } + + user, _, err = client.AdminCreateUser(opts) + if err != nil { + return + } + + d.SetId(fmt.Sprintf("%d", user.ID)) + + err = resourceUserUpdate(d, meta) + + return +} + +func resourceUserUpdate(d *schema.ResourceData, meta interface{}) (err error) { + client := meta.(*gitea.Client) + + id, err := strconv.ParseInt(d.Id(), 10, 64) + var resp *gitea.Response + var user *gitea.User + + user, resp, err = client.GetUserByID(id) + + if err != nil { + if resp.StatusCode == 404 { + resourceUserCreate(d, meta) + } else { + return err + } + } + + mail := d.Get(userEmail).(string) + fullName := d.Get(userFullName).(string) + description := d.Get(userDescription).(string) + changePassword := d.Get(userMustChangePassword).(bool) + location := d.Get(userLocation).(string) + active := d.Get(userActive).(bool) + admin := d.Get(userAdmin).(bool) + allowHook := d.Get(userAllowGitHook).(bool) + allowImport := d.Get(userAllowLocalImport).(bool) + maxRepoCreation := d.Get(userMaxRepoCreation).(int) + accessDenied := d.Get(userPhorbitLogin).(bool) + allowOrgs := d.Get(userAllowCreateOrgs).(bool) + restricted := d.Get(userRestricted).(bool) + visibility := gitea.VisibleType(d.Get(userVisibility).(string)) + + if d.Get(userForcePasswordChange).(bool) { + opts := gitea.EditUserOption{ + SourceID: 0, + LoginName: d.Get(userLoginName).(string), + Email: &mail, + FullName: &fullName, + Password: d.Get(userPassword).(string), + Description: &description, + MustChangePassword: &changePassword, + Location: &location, + Active: &active, + Admin: &admin, + AllowGitHook: &allowHook, + AllowImportLocal: &allowImport, + MaxRepoCreation: &maxRepoCreation, + ProhibitLogin: &accessDenied, + AllowCreateOrganization: &allowOrgs, + Restricted: &restricted, + Visibility: &visibility, + } + _, err = client.AdminEditUser(d.Get(userName).(string), opts) + + if err != nil { + return err + } + + } else { + opts := gitea.EditUserOption{ + SourceID: 0, + LoginName: d.Get(userLoginName).(string), + Email: &mail, + FullName: &fullName, + Description: &description, + MustChangePassword: &changePassword, + Location: &location, + Active: &active, + Admin: &admin, + AllowGitHook: &allowHook, + AllowImportLocal: &allowImport, + MaxRepoCreation: &maxRepoCreation, + ProhibitLogin: &accessDenied, + AllowCreateOrganization: &allowOrgs, + Restricted: &restricted, + Visibility: &visibility, + } + _, err = client.AdminEditUser(d.Get(userName).(string), opts) + + if err != nil { + return err + } + } + + user, _, err = client.GetUserByID(id) + + err = setUserResourceData(user, d) + + return +} + +func resourceUserDelete(d *schema.ResourceData, meta interface{}) (err error) { + client := meta.(*gitea.Client) + + var resp *gitea.Response + + resp, err = client.AdminDeleteUser(d.Get(userName).(string)) + + if err != nil { + if resp.StatusCode == 404 { + return + } else { + return err + } + } + + return +} + +func setUserResourceData(user *gitea.User, d *schema.ResourceData) (err error) { + d.SetId(fmt.Sprintf("%d", user.ID)) + d.Set("id", user.ID) + d.Set(userName, user.UserName) + d.Set(userEmail, user.Email) + d.Set(userFullName, user.FullName) + d.Set(userAdmin, user.IsAdmin) + d.Set("created", user.Created) + d.Set("avatar_url", user.AvatarURL) + d.Set("last_login", user.LastLogin) + d.Set("language", user.Language) + d.Set(userLoginName, d.Get(userLoginName).(string)) + d.Set(userMustChangePassword, d.Get(userMustChangePassword).(bool)) + d.Set(userSendNotification, d.Get(userSendNotification).(bool)) + d.Set(userVisibility, d.Get(userVisibility).(string)) + d.Set(userDescription, d.Get(userDescription).(string)) + d.Set(userLocation, d.Get(userLocation).(string)) + d.Set(userActive, d.Get(userActive).(bool)) + d.Set(userAllowGitHook, d.Get(userAllowGitHook).(bool)) + d.Set(userAllowLocalImport, d.Get(userAllowLocalImport).(bool)) + d.Set(userMaxRepoCreation, d.Get(userMaxRepoCreation).(int)) + d.Set(userPhorbitLogin, d.Get(userPhorbitLogin).(bool)) + d.Set(userAllowCreateOrgs, d.Get(userAllowCreateOrgs).(bool)) + d.Set(userRestricted, d.Get(userRestricted).(bool)) + d.Set(userForcePasswordChange, d.Get(userForcePasswordChange).(bool)) + + return +} + +func resourceGiteaUser() *schema.Resource { + return &schema.Resource{ + Read: resourceUserRead, + Create: resourceUserCreate, + Update: resourceUserUpdate, + Delete: resourceUserDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + Schema: map[string]*schema.Schema{ + "username": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Username of the user to be created", + }, + "login_name": { + Type: schema.TypeString, + Optional: false, + Required: true, + Description: "The login name can differ from the username", + }, + "email": { + Type: schema.TypeString, + Optional: false, + Required: true, + Description: "E-Mail Address of the user", + }, + "full_name": { + Type: schema.TypeString, + Computed: true, + Optional: true, + Required: false, + Description: "Full name of the user", + }, + "password": { + Type: schema.TypeString, + Optional: false, + Required: true, + Sensitive: true, + Description: "Password to be set for the user", + }, + "must_change_password": { + Type: schema.TypeBool, + Optional: true, + Required: false, + Default: true, + Description: "Flag if the user should change the password after first login", + }, + "send_notification": { + Type: schema.TypeBool, + Optional: true, + Required: false, + Default: true, + Description: "Flag to send a notification about the user creation to the defined `email`", + }, + "visibility": { + Type: schema.TypeString, + Optional: true, + Required: false, + Default: "public", + Description: "Visibility of the user. Can be `public`, `limited` or `private`", + }, + "description": { + Type: schema.TypeString, + Optional: true, + Required: false, + Default: "", + Description: "A description of the user", + }, + "location": { + Type: schema.TypeString, + Optional: true, + Required: false, + Default: "", + }, + "active": { + Type: schema.TypeBool, + Optional: true, + Required: false, + Default: true, + Description: "Flag if this user should be active or not", + }, + "admin": { + Type: schema.TypeBool, + Optional: true, + Required: false, + Default: false, + Description: "Flag if this user should be an administrator or not", + }, + "allow_git_hook": { + Type: schema.TypeBool, + Optional: true, + Required: false, + Default: true, + }, + "allow_import_local": { + Type: schema.TypeBool, + Optional: true, + Required: false, + Default: true, + }, + "max_repo_creation": { + Type: schema.TypeInt, + Optional: true, + Required: false, + Default: -1, + }, + "prohibit_login": { + Type: schema.TypeBool, + Optional: true, + Required: false, + Default: false, + Description: "Flag if the user should not be allowed to log in (bot user)", + }, + "allow_create_organization": { + Type: schema.TypeBool, + Optional: true, + Required: false, + Default: true, + }, + "restricted": { + Type: schema.TypeBool, + Optional: true, + Required: false, + Default: false, + }, + "force_password_change": { + Type: schema.TypeBool, + Optional: true, + Required: false, + Default: false, + Description: "Flag if the user defined password should be overwritten or not", + }, + }, + Description: "`gitea_user` manages a native gitea user.\n\n" + + "If you are using OIDC or other kinds of authentication mechanisms you can still try to manage" + + "ssh keys or other ressources this way", + } +}