@@ -1576,3 +1576,398 @@ func TestUserResolver_TotalPoints(t *testing.T) {
15761576 require .Equal (t , 200 , totalPoints2 )
15771577 })
15781578}
1579+
1580+ func TestMutationResolver_CreateCheatRecord (t * testing.T ) {
1581+ t .Run ("success - create for self" , func (t * testing.T ) {
1582+ entClient := testhelper .NewEntSqliteClient (t )
1583+
1584+ // Create test group
1585+ group , err := createTestGroup (t , entClient )
1586+ require .NoError (t , err )
1587+
1588+ // Create a test user
1589+ user , err := entClient .User .Create ().
1590+ SetName ("testuser" ).
1591+ SetEmail ("test@example.com" ).
1592+ SetGroup (group ).
1593+ Save (context .Background ())
1594+ require .NoError (t , err )
1595+
1596+ resolver := NewTestResolver (t , entClient , & mockAuthStorage {})
1597+
1598+ // Create test server with scope directive
1599+ cfg := Config {
1600+ Resolvers : resolver ,
1601+ Directives : DirectiveRoot {Scope : directive .ScopeDirective },
1602+ }
1603+ srv := handler .New (NewExecutableSchema (cfg ))
1604+ srv .AddTransport (transport.POST {})
1605+ c := client .New (srv )
1606+
1607+ // Execute mutation
1608+ var resp struct {
1609+ CreateCheatRecord struct {
1610+ ID string
1611+ Reason string
1612+ UserID int
1613+ }
1614+ }
1615+ err = c .Post (`mutation { createCheatRecord(reason: "Test cheating reason") { id reason userID } }` , & resp , func (bd * client.Request ) {
1616+ bd .HTTP = bd .HTTP .WithContext (auth .WithUser (bd .HTTP .Context (), auth.TokenInfo {
1617+ UserID : user .ID ,
1618+ Scopes : []string {"me:write" },
1619+ }))
1620+ })
1621+
1622+ // Verify response
1623+ require .NoError (t , err )
1624+ require .NotEmpty (t , resp .CreateCheatRecord .ID )
1625+ require .Equal (t , "Test cheating reason" , resp .CreateCheatRecord .Reason )
1626+ require .Equal (t , user .ID , resp .CreateCheatRecord .UserID )
1627+ })
1628+
1629+ t .Run ("success - create for another user" , func (t * testing.T ) {
1630+ entClient := testhelper .NewEntSqliteClient (t )
1631+
1632+ // Create test group
1633+ group , err := createTestGroup (t , entClient )
1634+ require .NoError (t , err )
1635+
1636+ // Create a test user
1637+ targetUser , err := entClient .User .Create ().
1638+ SetName ("targetuser" ).
1639+ SetEmail ("target@example.com" ).
1640+ SetGroup (group ).
1641+ Save (context .Background ())
1642+ require .NoError (t , err )
1643+
1644+ resolver := NewTestResolver (t , entClient , & mockAuthStorage {})
1645+
1646+ // Create test server with scope directive
1647+ cfg := Config {
1648+ Resolvers : resolver ,
1649+ Directives : DirectiveRoot {Scope : directive .ScopeDirective },
1650+ }
1651+ srv := handler .New (NewExecutableSchema (cfg ))
1652+ srv .AddTransport (transport.POST {})
1653+ c := client .New (srv )
1654+
1655+ // Execute mutation
1656+ var resp struct {
1657+ CreateCheatRecord struct {
1658+ ID string
1659+ Reason string
1660+ UserID int
1661+ }
1662+ }
1663+ err = c .Post (`mutation { createCheatRecord(userID: ` + strconv .Itoa (targetUser .ID )+ `, reason: "Test cheating reason") { id reason userID } }` , & resp , func (bd * client.Request ) {
1664+ bd .HTTP = bd .HTTP .WithContext (auth .WithUser (bd .HTTP .Context (), auth.TokenInfo {
1665+ UserID : 1 ,
1666+ Scopes : []string {"cheat_record:write" },
1667+ }))
1668+ })
1669+
1670+ // Verify response
1671+ require .NoError (t , err )
1672+ require .NotEmpty (t , resp .CreateCheatRecord .ID )
1673+ require .Equal (t , "Test cheating reason" , resp .CreateCheatRecord .Reason )
1674+ require .Equal (t , targetUser .ID , resp .CreateCheatRecord .UserID )
1675+ })
1676+
1677+ t .Run ("unauthenticated" , func (t * testing.T ) {
1678+ entClient := testhelper .NewEntSqliteClient (t )
1679+
1680+ resolver := NewTestResolver (t , entClient , & mockAuthStorage {})
1681+
1682+ // Create test server with scope directive
1683+ cfg := Config {
1684+ Resolvers : resolver ,
1685+ Directives : DirectiveRoot {Scope : directive .ScopeDirective },
1686+ }
1687+ srv := handler .New (NewExecutableSchema (cfg ))
1688+ srv .AddTransport (transport.POST {})
1689+ c := client .New (srv )
1690+
1691+ // Execute mutation with no auth context
1692+ var resp struct {
1693+ CreateCheatRecord struct {
1694+ ID string
1695+ }
1696+ }
1697+ err := c .Post (`mutation { createCheatRecord(reason: "Test reason") { id } }` , & resp )
1698+
1699+ // Verify error
1700+ require .Error (t , err )
1701+ require .Contains (t , err .Error (), defs .CodeUnauthorized )
1702+ })
1703+
1704+ t .Run ("insufficient scope - create for self without me:write" , func (t * testing.T ) {
1705+ entClient := testhelper .NewEntSqliteClient (t )
1706+
1707+ // Create test group
1708+ group , err := createTestGroup (t , entClient )
1709+ require .NoError (t , err )
1710+
1711+ // Create a test user
1712+ user , err := entClient .User .Create ().
1713+ SetName ("testuser" ).
1714+ SetEmail ("test@example.com" ).
1715+ SetGroup (group ).
1716+ Save (context .Background ())
1717+ require .NoError (t , err )
1718+
1719+ resolver := NewTestResolver (t , entClient , & mockAuthStorage {})
1720+
1721+ // Create test server with scope directive
1722+ cfg := Config {
1723+ Resolvers : resolver ,
1724+ Directives : DirectiveRoot {Scope : directive .ScopeDirective },
1725+ }
1726+ srv := handler .New (NewExecutableSchema (cfg ))
1727+ srv .AddTransport (transport.POST {})
1728+ c := client .New (srv )
1729+
1730+ // Execute mutation
1731+ var resp struct {
1732+ CreateCheatRecord struct {
1733+ ID string
1734+ }
1735+ }
1736+ err = c .Post (`mutation { createCheatRecord(reason: "Test reason") { id } }` , & resp , func (bd * client.Request ) {
1737+ bd .HTTP = bd .HTTP .WithContext (auth .WithUser (bd .HTTP .Context (), auth.TokenInfo {
1738+ UserID : user .ID ,
1739+ Scopes : []string {"user:read" },
1740+ }))
1741+ })
1742+
1743+ // Verify error
1744+ require .Error (t , err )
1745+ require .Contains (t , err .Error (), defs .CodeForbidden )
1746+ require .Contains (t , err .Error (), "me:write" )
1747+ })
1748+
1749+ t .Run ("insufficient scope - create for another user without cheat_record:write" , func (t * testing.T ) {
1750+ entClient := testhelper .NewEntSqliteClient (t )
1751+
1752+ // Create test group
1753+ group , err := createTestGroup (t , entClient )
1754+ require .NoError (t , err )
1755+
1756+ // Create a test user
1757+ targetUser , err := entClient .User .Create ().
1758+ SetName ("targetuser" ).
1759+ SetEmail ("target@example.com" ).
1760+ SetGroup (group ).
1761+ Save (context .Background ())
1762+ require .NoError (t , err )
1763+
1764+ resolver := NewTestResolver (t , entClient , & mockAuthStorage {})
1765+
1766+ // Create test server with scope directive
1767+ cfg := Config {
1768+ Resolvers : resolver ,
1769+ Directives : DirectiveRoot {Scope : directive .ScopeDirective },
1770+ }
1771+ srv := handler .New (NewExecutableSchema (cfg ))
1772+ srv .AddTransport (transport.POST {})
1773+ c := client .New (srv )
1774+
1775+ // Execute mutation
1776+ var resp struct {
1777+ CreateCheatRecord struct {
1778+ ID string
1779+ }
1780+ }
1781+ err = c .Post (`mutation { createCheatRecord(userID: ` + strconv .Itoa (targetUser .ID )+ `, reason: "Test reason") { id } }` , & resp , func (bd * client.Request ) {
1782+ bd .HTTP = bd .HTTP .WithContext (auth .WithUser (bd .HTTP .Context (), auth.TokenInfo {
1783+ UserID : 1 ,
1784+ Scopes : []string {"user:read" },
1785+ }))
1786+ })
1787+
1788+ // Verify error
1789+ require .Error (t , err )
1790+ require .Contains (t , err .Error (), defs .CodeForbidden )
1791+ require .Contains (t , err .Error (), "cheat_record:write" )
1792+ })
1793+ }
1794+
1795+ func TestMutationResolver_ResolveCheatRecord (t * testing.T ) {
1796+ t .Run ("success" , func (t * testing.T ) {
1797+ entClient := testhelper .NewEntSqliteClient (t )
1798+
1799+ // Create test group
1800+ group , err := createTestGroup (t , entClient )
1801+ require .NoError (t , err )
1802+
1803+ // Create a test user
1804+ user , err := entClient .User .Create ().
1805+ SetName ("testuser" ).
1806+ SetEmail ("test@example.com" ).
1807+ SetGroup (group ).
1808+ Save (context .Background ())
1809+ require .NoError (t , err )
1810+
1811+ // Create a cheat record
1812+ cheatRecord , err := entClient .CheatRecord .Create ().
1813+ SetUser (user ).
1814+ SetReason ("Initial cheating reason" ).
1815+ Save (context .Background ())
1816+ require .NoError (t , err )
1817+
1818+ resolver := NewTestResolver (t , entClient , & mockAuthStorage {})
1819+
1820+ // Create test server with scope directive
1821+ cfg := Config {
1822+ Resolvers : resolver ,
1823+ Directives : DirectiveRoot {Scope : directive .ScopeDirective },
1824+ }
1825+ srv := handler .New (NewExecutableSchema (cfg ))
1826+ srv .AddTransport (transport.POST {})
1827+ c := client .New (srv )
1828+
1829+ // Execute mutation
1830+ var resp struct {
1831+ ResolveCheatRecord bool
1832+ }
1833+ err = c .Post (`mutation { resolveCheatRecord(cheatRecordID: ` + strconv .Itoa (cheatRecord .ID )+ `, reason: "Resolved - false alarm") }` , & resp , func (bd * client.Request ) {
1834+ bd .HTTP = bd .HTTP .WithContext (auth .WithUser (bd .HTTP .Context (), auth.TokenInfo {
1835+ UserID : 1 ,
1836+ Scopes : []string {"cheat_record:write" },
1837+ }))
1838+ })
1839+
1840+ // Verify response
1841+ require .NoError (t , err )
1842+ require .True (t , resp .ResolveCheatRecord )
1843+
1844+ // Verify the cheat record was actually resolved
1845+ resolvedRecord , err := entClient .CheatRecord .Get (context .Background (), cheatRecord .ID )
1846+ require .NoError (t , err )
1847+ require .NotNil (t , resolvedRecord .ResolvedAt )
1848+ require .Equal (t , "Resolved - false alarm" , resolvedRecord .ResolvedReason )
1849+ })
1850+
1851+ t .Run ("unauthenticated" , func (t * testing.T ) {
1852+ entClient := testhelper .NewEntSqliteClient (t )
1853+
1854+ // Create test group
1855+ group , err := createTestGroup (t , entClient )
1856+ require .NoError (t , err )
1857+
1858+ // Create a test user
1859+ user , err := entClient .User .Create ().
1860+ SetName ("testuser" ).
1861+ SetEmail ("test@example.com" ).
1862+ SetGroup (group ).
1863+ Save (context .Background ())
1864+ require .NoError (t , err )
1865+
1866+ // Create a cheat record
1867+ cheatRecord , err := entClient .CheatRecord .Create ().
1868+ SetUser (user ).
1869+ SetReason ("Initial cheating reason" ).
1870+ Save (context .Background ())
1871+ require .NoError (t , err )
1872+
1873+ resolver := NewTestResolver (t , entClient , & mockAuthStorage {})
1874+
1875+ // Create test server with scope directive
1876+ cfg := Config {
1877+ Resolvers : resolver ,
1878+ Directives : DirectiveRoot {Scope : directive .ScopeDirective },
1879+ }
1880+ srv := handler .New (NewExecutableSchema (cfg ))
1881+ srv .AddTransport (transport.POST {})
1882+ c := client .New (srv )
1883+
1884+ // Execute mutation with no auth context
1885+ var resp struct {
1886+ ResolveCheatRecord bool
1887+ }
1888+ err = c .Post (`mutation { resolveCheatRecord(cheatRecordID: ` + strconv .Itoa (cheatRecord .ID )+ `, reason: "Resolved") }` , & resp )
1889+
1890+ // Verify error
1891+ require .Error (t , err )
1892+ require .Contains (t , err .Error (), defs .CodeUnauthorized )
1893+ })
1894+
1895+ t .Run ("insufficient scope" , func (t * testing.T ) {
1896+ entClient := testhelper .NewEntSqliteClient (t )
1897+
1898+ // Create test group
1899+ group , err := createTestGroup (t , entClient )
1900+ require .NoError (t , err )
1901+
1902+ // Create a test user
1903+ user , err := entClient .User .Create ().
1904+ SetName ("testuser" ).
1905+ SetEmail ("test@example.com" ).
1906+ SetGroup (group ).
1907+ Save (context .Background ())
1908+ require .NoError (t , err )
1909+
1910+ // Create a cheat record
1911+ cheatRecord , err := entClient .CheatRecord .Create ().
1912+ SetUser (user ).
1913+ SetReason ("Initial cheating reason" ).
1914+ Save (context .Background ())
1915+ require .NoError (t , err )
1916+
1917+ resolver := NewTestResolver (t , entClient , & mockAuthStorage {})
1918+
1919+ // Create test server with scope directive
1920+ cfg := Config {
1921+ Resolvers : resolver ,
1922+ Directives : DirectiveRoot {Scope : directive .ScopeDirective },
1923+ }
1924+ srv := handler .New (NewExecutableSchema (cfg ))
1925+ srv .AddTransport (transport.POST {})
1926+ c := client .New (srv )
1927+
1928+ // Execute mutation
1929+ var resp struct {
1930+ ResolveCheatRecord bool
1931+ }
1932+ err = c .Post (`mutation { resolveCheatRecord(cheatRecordID: ` + strconv .Itoa (cheatRecord .ID )+ `, reason: "Resolved") }` , & resp , func (bd * client.Request ) {
1933+ bd .HTTP = bd .HTTP .WithContext (auth .WithUser (bd .HTTP .Context (), auth.TokenInfo {
1934+ UserID : 1 ,
1935+ Scopes : []string {"user:read" },
1936+ }))
1937+ })
1938+
1939+ // Verify error
1940+ require .Error (t , err )
1941+ require .Contains (t , err .Error (), defs .NewErrNoSufficientScope ("cheat_record:write" ).Error ())
1942+ })
1943+
1944+ t .Run ("cheat record not found" , func (t * testing.T ) {
1945+ entClient := testhelper .NewEntSqliteClient (t )
1946+
1947+ resolver := NewTestResolver (t , entClient , & mockAuthStorage {})
1948+
1949+ // Create test server with scope directive
1950+ cfg := Config {
1951+ Resolvers : resolver ,
1952+ Directives : DirectiveRoot {Scope : directive .ScopeDirective },
1953+ }
1954+ srv := handler .New (NewExecutableSchema (cfg ))
1955+ srv .AddTransport (transport.POST {})
1956+ c := client .New (srv )
1957+
1958+ // Execute mutation with non-existent cheat record ID
1959+ var resp struct {
1960+ ResolveCheatRecord bool
1961+ }
1962+ err := c .Post (`mutation { resolveCheatRecord(cheatRecordID: 99999, reason: "Resolved") }` , & resp , func (bd * client.Request ) {
1963+ bd .HTTP = bd .HTTP .WithContext (auth .WithUser (bd .HTTP .Context (), auth.TokenInfo {
1964+ UserID : 1 ,
1965+ Scopes : []string {"cheat_record:write" },
1966+ }))
1967+ })
1968+
1969+ // Verify error
1970+ require .Error (t , err )
1971+ require .Contains (t , err .Error (), "not found" )
1972+ })
1973+ }
0 commit comments