129 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			129 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| using DysonNetwork.Shared.Auth;
 | |
| using DysonNetwork.Shared.Models;
 | |
| using DysonNetwork.Shared.Proto;
 | |
| using Grpc.Core;
 | |
| using Microsoft.AspNetCore.Authorization;
 | |
| using Microsoft.AspNetCore.Mvc;
 | |
| using Microsoft.EntityFrameworkCore;
 | |
| 
 | |
| namespace DysonNetwork.Develop.Identity;
 | |
| 
 | |
| [ApiController]
 | |
| [Route("/api/developers")]
 | |
| public class DeveloperController(
 | |
|     AppDatabase db,
 | |
|     PublisherService.PublisherServiceClient ps,
 | |
|     ActionLogService.ActionLogServiceClient als,
 | |
|     DeveloperService ds
 | |
| )
 | |
|     : ControllerBase
 | |
| {
 | |
|     [HttpGet("{name}")]
 | |
|     public async Task<ActionResult<SnDeveloper>> GetDeveloper(string name)
 | |
|     {
 | |
|         var developer = await ds.GetDeveloperByName(name);
 | |
|         if (developer is null) return NotFound();
 | |
|         return Ok(await ds.LoadDeveloperPublisher(developer));
 | |
|     }
 | |
| 
 | |
|     [HttpGet("{name}/stats")]
 | |
|     public async Task<ActionResult<DeveloperStats>> GetDeveloperStats(string name)
 | |
|     {
 | |
|         var developer = await ds.GetDeveloperByName(name);
 | |
|         if (developer is null) return NotFound();
 | |
| 
 | |
|         // Get custom apps count
 | |
|         var customAppsCount = await db.CustomApps
 | |
|             .Include(a => a.Project)
 | |
|             .Where(a => a.Project.DeveloperId == developer.Id)
 | |
|             .CountAsync();
 | |
| 
 | |
|         var stats = new DeveloperStats
 | |
|         {
 | |
|             TotalCustomApps = customAppsCount
 | |
|         };
 | |
| 
 | |
|         return Ok(stats);
 | |
|     }
 | |
| 
 | |
|     [HttpGet]
 | |
|     [Authorize]
 | |
|     public async Task<ActionResult<List<SnDeveloper>>> ListJoinedDevelopers()
 | |
|     {
 | |
|         if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
 | |
|         
 | |
|         var pubResponse = await ps.ListPublishersAsync(new ListPublishersRequest { AccountId = currentUser.Id });
 | |
|         var pubIds = pubResponse.Publishers.Select(p => p.Id).Select(Guid.Parse).ToList();
 | |
| 
 | |
|         var developerQuery = db.Developers
 | |
|             .Where(d => pubIds.Contains(d.PublisherId))
 | |
|             .AsQueryable();
 | |
|         
 | |
|         var totalCount = await developerQuery.CountAsync(); 
 | |
|         Response.Headers.Append("X-Total", totalCount.ToString());
 | |
|         
 | |
|         var developers = await developerQuery.ToListAsync();
 | |
| 
 | |
|         return Ok(await ds.LoadDeveloperPublisher(developers));
 | |
|     }
 | |
| 
 | |
|     [HttpPost("{name}/enroll")]
 | |
|     [Authorize]
 | |
|     [RequiredPermission("global", "developers.create")]
 | |
|     public async Task<ActionResult<SnDeveloper>> EnrollDeveloperProgram(string name)
 | |
|     {
 | |
|         if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
 | |
|         var accountId = Guid.Parse(currentUser.Id);
 | |
| 
 | |
|         SnPublisher? pub;
 | |
|         try
 | |
|         {
 | |
|             var pubResponse = await ps.GetPublisherAsync(new GetPublisherRequest { Name = name });
 | |
|             pub = SnPublisher.FromProtoValue(pubResponse.Publisher);
 | |
|         } catch (RpcException ex)
 | |
|         {
 | |
|             return NotFound(ex.Status.Detail);
 | |
|         }
 | |
| 
 | |
|         // Check if the user is an owner of the publisher
 | |
|         var permResponse = await ps.IsPublisherMemberAsync(new IsPublisherMemberRequest
 | |
|         {
 | |
|             PublisherId = pub.Id.ToString(),
 | |
|             AccountId = currentUser.Id,
 | |
|             Role = Shared.Proto.PublisherMemberRole.Owner
 | |
|         });
 | |
|         if (!permResponse.Valid) return StatusCode(403, "You must be the owner of the publisher to join the developer program");
 | |
| 
 | |
|         var hasDeveloper = await db.Developers.AnyAsync(d => d.PublisherId == pub.Id);
 | |
|         if (hasDeveloper) return BadRequest("Publisher is already in the developer program");
 | |
|         
 | |
|         var developer = new SnDeveloper
 | |
|         {
 | |
|             Id = Guid.NewGuid(),
 | |
|             PublisherId = pub.Id
 | |
|         };
 | |
| 
 | |
|         db.Developers.Add(developer);
 | |
|         await db.SaveChangesAsync();
 | |
| 
 | |
|         _ = als.CreateActionLogAsync(new CreateActionLogRequest
 | |
|         {
 | |
|             Action = "developers.enroll",
 | |
|             Meta = 
 | |
|             { 
 | |
|                 { "publisher_id", Google.Protobuf.WellKnownTypes.Value.ForString(pub.Id.ToString()) },
 | |
|                 { "publisher_name", Google.Protobuf.WellKnownTypes.Value.ForString(pub.Name) }
 | |
|             },
 | |
|             AccountId = currentUser.Id,
 | |
|             UserAgent = Request.Headers.UserAgent,
 | |
|             IpAddress = Request.HttpContext.Connection.RemoteIpAddress?.ToString()
 | |
|         });
 | |
| 
 | |
|         return Ok(await ds.LoadDeveloperPublisher(developer));
 | |
|     }
 | |
| 
 | |
|     public class DeveloperStats
 | |
|     {
 | |
|         public int TotalCustomApps { get; set; }
 | |
|     }
 | |
| } |